From 136f09029ddd22eb9d8398db509cea2dac825e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ertu=C4=9Frul=20Erata?= Date: Thu, 30 Mar 2017 11:58:10 +0300 Subject: [PATCH] kernel 4.9.18 not ready --- kernel/kernel/actions.py | 24 - .../kernel/files/configs/kernel-x86_64-config | 7 +- .../files/patches/linux/patch-4.9.18.xz | Bin 0 -> 412000 bytes ...rr-Remove-kernel-internal-MTRR-inter.patch | 70 - ...x-acpi_ev_initialize_region-return-v.patch | 192 + ...t-NVMe-controller-in-recent-MacBooks.patch | 34 + ...-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch | 38 + ...-amd-amdgpu-add-Polaris12-support-v3.patch | 469 + ...eck-for-headless-before-calling-comp.patch | 32 + ...dgpu-powerplay-add-Polaris12-support.patch | 81 + ...sableLSQCROPERFforOCL-KBL-workaround.patch | 97 - ...arn-about-Skylake-CPU-KabyPoint-PCH-.patch | 42 + ...-workarounds-for-A0-and-B0-revisions.patch | 127 - ...skl-drop-workarounds-for-D0-revision.patch | 86 - ...skl-drop-workarounds-for-E0-revision.patch | 59 - .../files/patches/mageia/net-wireguard.patch | 11839 ++++++++++++++++ ...ix-incorrect-event-channel-deduction.patch | 29 - ...eless-realtek-rtl8xxxu-linux-4.11-rc.patch | 371 + ...klist-AMD-Stoney-GPU-devices-for-ATS.patch | 43 + kernel/kernel/files/patches/mageia/series | 47 +- ...-hda-realtek-Add-new-codec-ID-ALC299.patch | 102 + ...realtek-New-codec-support-of-ALC1220.patch | 45 + ...vt-switch-with-video-1366x768-option.patch | 71 - ...on-skl-when-the-plane-is-not-visible.patch | 49 - ...th-1s-delay-if-we-have-delayed-event.patch | 55 - ...ev-color-map-copying-bounds-checking.patch | 82 - ...ous-registers-for-short-regset-write.patch | 32 - kernel/kernel/pspec.xml | 39 +- .../files/patches/linux/patch-4.9.18.xz | Bin 0 -> 412000 bytes ...rr-Remove-kernel-internal-MTRR-inter.patch | 70 - ...x-acpi_ev_initialize_region-return-v.patch | 192 + ...t-NVMe-controller-in-recent-MacBooks.patch | 34 + ...-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch | 38 + ...-amd-amdgpu-add-Polaris12-support-v3.patch | 469 + ...eck-for-headless-before-calling-comp.patch | 32 + ...dgpu-powerplay-add-Polaris12-support.patch | 81 + ...sableLSQCROPERFforOCL-KBL-workaround.patch | 97 - ...arn-about-Skylake-CPU-KabyPoint-PCH-.patch | 42 + ...-workarounds-for-A0-and-B0-revisions.patch | 127 - ...skl-drop-workarounds-for-D0-revision.patch | 86 - ...skl-drop-workarounds-for-E0-revision.patch | 59 - .../files/patches/mageia/net-wireguard.patch | 11839 ++++++++++++++++ ...ix-incorrect-event-channel-deduction.patch | 29 - ...eless-realtek-rtl8xxxu-linux-4.11-rc.patch | 371 + ...klist-AMD-Stoney-GPU-devices-for-ATS.patch | 43 + .../cpupowertools/files/patches/mageia/series | 47 +- ...-hda-realtek-Add-new-codec-ID-ALC299.patch | 102 + ...realtek-New-codec-support-of-ALC1220.patch | 45 + ...vt-switch-with-video-1366x768-option.patch | 71 - ...on-skl-when-the-plane-is-not-visible.patch | 49 - ...th-1s-delay-if-we-have-delayed-event.patch | 55 - ...ev-color-map-copying-bounds-checking.patch | 82 - ...ous-registers-for-short-regset-write.patch | 32 - kernel/tools/cpupowertools/pspec.xml | 36 +- 54 files changed, 26685 insertions(+), 1605 deletions(-) create mode 100644 kernel/kernel/files/patches/linux/patch-4.9.18.xz delete mode 100644 kernel/kernel/files/patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch create mode 100644 kernel/kernel/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch create mode 100644 kernel/kernel/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch create mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch create mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch create mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch create mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch delete mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch create mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch delete mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch delete mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch delete mode 100644 kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch create mode 100644 kernel/kernel/files/patches/mageia/net-wireguard.patch delete mode 100644 kernel/kernel/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch create mode 100644 kernel/kernel/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch create mode 100644 kernel/kernel/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch create mode 100644 kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch create mode 100644 kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch delete mode 100644 kernel/kernel/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch delete mode 100644 kernel/kernel/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch delete mode 100644 kernel/kernel/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch delete mode 100644 kernel/kernel/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch delete mode 100644 kernel/kernel/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch create mode 100644 kernel/tools/cpupowertools/files/patches/linux/patch-4.9.18.xz delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/net-wireguard.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch delete mode 100644 kernel/tools/cpupowertools/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch diff --git a/kernel/kernel/actions.py b/kernel/kernel/actions.py index 589711c1..e4aedaef 100644 --- a/kernel/kernel/actions.py +++ b/kernel/kernel/actions.py @@ -34,27 +34,3 @@ def install(): # Generate some module lists to use within mkinitramfs shelltools.system("./generate-module-list %s/lib/modules/%s" % (get.installDIR(), kerneltools.__getSuffix())) - - - - #mkinitcpio default config - pisitools.dodir("/etc/mkinitcpio.d") - shelltools.touch("linux.preset") - - - shelltools.echo("linux.preset", "# mkinitcpio preset file for the 'linux' package\n" + - - 'ALL_config="/etc/mkinitcpio.conf"\n'+ - - 'ALL_kver="/boot/kernel-%s"\n\n'% get.srcVERSION() + - "PRESETS=('default' 'fallback') \n\n" + - '#default_config="/etc/mkinitcpio.conf"\n' + - - 'default_image="/boot/initramfs-%s.img"\n'% get.srcVERSION() + - - '#default_options=""\n\n' + - '#fallback_config="/etc/mkinitcpio.conf"\n'+ - 'fallback_image="/boot/initramfs-%s-fallback.img"\n'% get.srcVERSION() + - 'fallback_options="-S autodetect"\n') - - pisitools.insinto("/etc/mkinitcpio.d", "linux.preset") diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config index 724d16e5..0e7cf7b6 100644 --- a/kernel/kernel/files/configs/kernel-x86_64-config +++ b/kernel/kernel/files/configs/kernel-x86_64-config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 4.9.6 Kernel Configuration +# Linux/x86_64 4.9.18 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y @@ -373,8 +373,6 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y CONFIG_CFQ_GROUP_IOSCHED=y -CONFIG_IOSCHED_BFQ=m -# CONFIG_BFQ_GROUP_IOSCHED is not set CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set @@ -849,6 +847,9 @@ CONFIG_XFRM_IPCOMP=m CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y +CONFIG_WIREGUARD=m +CONFIG_WIREGUARD_PARALLEL=y +# CONFIG_WIREGUARD_DEBUG is not set CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_FIB_TRIE_STATS=y diff --git a/kernel/kernel/files/patches/linux/patch-4.9.18.xz b/kernel/kernel/files/patches/linux/patch-4.9.18.xz new file mode 100644 index 0000000000000000000000000000000000000000..52032c3ccb5e508c2912404f3eb56089e795e703 GIT binary patch literal 412000 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

P8g#0@C0V92u zaPwRlK_2+(*YgoiwhEA|<75SUJ>Ao}NXTHo(@R=FhxQY(9lFQ7(l<8h|1AIDWaJakTAariC25Pzk%bYugU3P&KT9`bF*ATtmB?Eg zW@AjkDTpn22Ki?dv@4oiy@?dEm_C}#{XYJy!t-yUQ?{Elzz8lIAU6J6c)%LuetXq4 zw+`xv)HPR?RX@=Wh=nr@;xyTd#x==5IyP!Sk`45w*ZvHJi%^C{5&U7XF0ccxMhMz) z0p+W83MMwtjezcV&m{;rpRJpqhAQH&mSV7#|E>)dN3_w5RQmx7Fl`ApPGh@Ck3{$@ z-*N1kPV%MnQ*W(Lj3C5d%XY7#-89u`9Im+ZU+D^C;2LzjR4BVx}$Z3l`J= zwy!`X1(iG@mk&x3i3iFCF?;){)BPX`3MF7FJf`>hh^!`re0cU7x|u95medV%M>Ub= zc4vv!3_~pz?sK8Q9{-4^>b#xKRmfIhcQx=YJ2nI2JIHOj0v*D%Dks5Z(RMvJe96Er ze>#kAb7jf_Mj?@5V*JwFl4?ClOgZ%w1v|XGNrym7j5~Jf}8H}8@q`zqvyuWP) zKCR?g6ln2Em@|O`e=qi>O}WF8t9$6z~a#aPn65Ku-fNbbhX-WzVIAFW0 zAvgw&Ch<$&o}`%4XBr9isqGjC(7muJmkv-)#~RaHXBA>#+s+`^c)S@~ zfqH?wkTDn%?Qu6DaqacE64sxmnVOG#iir3X9_P1CACsgDX54v$9=*QR_|g8sYR(T_AxiGE_Z*TBD|q1* z+m$n@ijefEgD7;CZw}CbZw65IX+O5fl2sY7GLg)t-KH^a7(|b{W8VNXJajcF)TT04 zeNtooYXbOS(v96T-4U>IDqzT0NHeELy(ZnJE#zSlo(&oL?{wpY$DV~~T;9}jBV*M$ zdFo{t5BhhQ)t^4RQk|=U{u#7Kc~sQK3;x^*fPev-?~uP0WA%k#;A~ zb^6h~*`4-+Oqjgo6{WpsgAO=gqcCy~6}M(wlg5&K z0QXC)$_Di|XD+N2n0y|*&zkI~9D_XSt~u|doi$7tsz-0`asR7M@1ipxmdobi!xJh~8#8urSJ6X(a+1YEc{>iz9H_>)L}+X#2K`H%=wqJc7r32EC$ggk zGc-*l3NZ5Q==hnw=Oi!X^VzFMNCMc+uDv+?22e~ZN6&g)QrSBNAzX%Rh>RYZTdRL6 zGwV;)#wK|Ru&$AnWnHhM|0?qOUoR~wlNY!EaAldLAm_z|W{+5g=}w)n2dVfjU>xB@ zm70ea(8fXRB$^dfh~CqeE%5G|FKtg9Nqgk?_U&c>o67Hewx^WfVFbhB^$=j1%x zs8z=aLqEChz%TN{*zt$5*|5D!kP9&|n^)j_x6 zJ7PRCBr+9v z0XL){IS5Z%nu1_q32z-q!^_vWU)su&$m6m*17cbP-Q*6Xvg;zl^SG)Ury(7(ka{A~ zr^b~2F4O;I-DM&M#vBF^2eMKKm1Xmz1=iq%^k{?iy0qO!D0Gp6t0Bg*S0UvV|D6G2goEf3%AeMH3lYHS{B}BQG$DK$=OVvLjOxVS>z%PW0v({ zo4sN8O?Af7EX1_s0S~F!OsU85(Yc@)WQAF!g(3VCzFPx9WjTD?^Px(mWDG7{YoL9V ziwJmv90oAOn;-|51t?l@+b&7soI|31p7vqgN8Vbvv$rmY3IuVdGpstkW&lGPfs=b) z7ec7eMT=>UkiF0^m9QYpu#FScqc5fYSt{S~fbmv4Y+9WjM@~i71`=1o_E^LKGTt`@ zjJ@&o{?=DMBefeX5%zW`I1HOYf`CaW?;-)*H5NOsBQJ;fo&og4gb2Hp*bwqi7Gu7A zJIq`33^!ATX%cT2MUW3JEBc-~p<3>IX>=0~FI=e#vfE*Ce922@Qv3QgH38q8+AeMyoS^D_t! z%wF#YajIYXLz5_sHV!m-TgC<5?JaqSxs<|_PcSKX?~sO4)=p5HNbw$Dwn=XAa%9Sb z(ja0wDWvY$V(oq1{^2KPX;QTPI-1=2vsN^j%bA{uETMIFo>V4?B^k~38`buc0D9YF z$mO+;2m0NC)LZrRV0DgL26EIpn0RFO;v))c_={ATUYyH3PBZKHL%3DQnoxQ z>%}@HYcsS-^S>%6$t_vTOawxeG@l|6iy0a6A$jeP^gE=3CHK%D)^ zp(Gxn;|K7wlUX3Zjnkw=3R+2exervZJ=Q^JQRU2b_TfVK;q?laR|)&IDo@XeUv!XX ztfv*8oJZE=>ETvjLl@A5o0I=F6E6yt11>~?F2&^mf{EB57WWGJIK(K4q%c&#%X49b z!38zQxAp^m&$qWrEp#O{92brJtu@_~{OJ-cuAfH;4gg1NSM0yWOozersP{y*`B-qo z@i*h3z%kKfPpd1VJv3g?vpba^LQail|Iz1RJT=kE+?rfT%5)~SA2oG*J+;$F{7P^Q z4g8|LBy0X`B20OSEj$C6sC{t$mw9mA9%YsF>J*3LHF`;$T&H5 zQo^{RK+_pTNbH9f+Ib_49rYkxs5n>rX*3uW@t^74!s5>kVdzB<mAxfXdF1RciM9RLluM;eW^WV?%IKIGn>di#>|F&+Loe;q!h#d6at1zrxeWb$ zyA!FcSKlOGcR|%CI>zpM0xIcRw%E;?@@-6B(nY^ulRlRT4(pryn)Jodr3IN+0Qekl^y}A`ZT3E)$UI*L$^%C6< z-Kk_iJmVWKQ-athCU#<&$%>~6!Dqn*0Wh-RXCBBVJI9Do>$ih3Y!lGBbKBV1P{D)Gf+;=Ht8Cup8!;BXh+1$~lusF6;T`5UWHQ%_Pyl4t4vyozun^@-0E(+~zCL+r1@e{jV0QQwDWv#8%wD}3{Fsz(> z`(@V$x%8?Cq5VysZM^Rp(z{wf$-2^D9hRJ6V-@*2QAYiW*JJ za^x7*R%F+#ny~_g7d@;Hfd*$9zbLjR`>ApyV$|ViO@AB@I2gS$z^>oUv`M@DsXaSK zPQ%+e+6li`0v!;c!YG#cV>KHGx9@Z609?tgeIb83B7X>P=_M~UFro?vuMJC^&iXy_ zQ|Fi=P@}|hVoEd3*-$0&>uhO+rV7p4SjWwx9IkC0FSUGyo8oNwqB&@>wv!M8RBMZ{ zOIw6udY>nN_E_I_^|#b!As8fSbXqBj9|@@M+wNQWY_Ej})eb5YnRUk*j)1-*VXoiN zYj@+Mn}G^#Tu%`q{B!9Vy zYbiyY;Tk-h$3=S%*H5m_WX6D>iLibwY3LoEC_#Ec5oMeVnB>$vwA${mGCevuDZB1} zrzdGEAz`m`=(+~eeGfV|%xJQDPC&YYy(V?4FWFCH27|QBY2adw|Mn+UPh6fh(C^W5Tq!Y^|^~aa(+R=mv&jv z*4l>En{|y27xU+2^R$*zp??}|VUCc}QLOu^tFnHKmp-)6Q(A(WJ zuv-DT!8tYW>9T!dZQe6*4muFiHG3dSwI4yXSSlH8ln*3-he36)w4Q8PQYP}F4078Y zb_B6o%?0>Zn|(H0yA1Fi0V|WAmd>P~{A;4IqM@5&4HXz+dLTEv6_<1pe#H!KYjI^! z;w^A^9)wPjG+`wao96VdTsP1Gk4D0D&x(d5y(n6Qa`9|nsLulU9bN^v9h>2plhLtn z=XWc*hmMDm_N$dmGHlC(V^*Sv{)?^%w49icT$`a)nLh=Awc9z<;*YkD^A}riU|d=_ zTj7GcYAG{5hcY0lPYm(gSNGVfKac5X-i1J_9z>N8FL;Xh`u;2aSO;`>pU5acZEE8^ z6m~tR?|>Dh{5+`i86(nCG|g`&@WM9v?HpxLcWms##%0W>W71wd!Gmq2rc>^`pizYK zGlIHOpM=mWXyE0-Q^0F5Q*gUs?oV1xu2p;rjht82TYyU82hICUE(#A#>93ArOV;V* ztBM9C884#@LR$Mj@hubL7d&mKqQc|prbeWUo;GGbUYqcUT4e(0+Kc&uJ!*A^md{tV z5M$RS3l1NS+0bMX0PICRvQ%;%kvLhuKiM;ROJ z5?E89QfPx%4mjWpAwxl7p@)|=3# zEyBR^0kolsz;*ke!iINMC%C(NpF8@=EkvQ;d1QDALzs|7itObbRgMYT@{rM6#P5h8 zVa?m+IVF6TTcA-TJC_WeYZ9Z|tbMgrx~G4>j==fV&#%Zode&r@!^DmJnaeg0?()93oHpABWQ5dk+^J5GQB~`YB5d0k zCDAz}C=pMSqzlI5A&4N2w`?xuCNb?J-7S=R+{SBdCHATR@73xVowOfQH$j2IKuKP0 z-G_K-FBDirCg+lblL$TmVJYIp2_V9}hef&*RLzSTlw~OZ;f^Syu2GE+1yksah)Tp$ zezl2=F%afj>@%lY3-B81=k8G*7i(Lf=$~X{XMdrlts4YJ?t-f=BlNWSHLs=ZrTbHL z7l=bj3Ouo}U_!aXl~~g)(YzBPX88w)ss7FR*J%9zW{w^F4FIzHmG zsh0h(>qjG!a{29YZJ+(_q!r~8FJR2cH{!k&DhGLYah14tJzZgOkeU4(HT zkTWo5W#X&hH2;70eHZcZ>yC+`bb7Q~KDXY0lEBRLt?m`1e}B1HNo{Jo_T(h=up1G@ zk`=d0EiK=mW$eXPH7WJYUDMI*MmE(5YqAN%Iffhf<fbeG!3>wsZL1wMao;0l3T+m4r8D3N|?90WPDkL$MPO@2wHEN zZKd(K^VfpWW>3N&x1!H)K360d%3&eX?W9eB+!+93mMWzpkERi!b(=a6nFk{=SLe~ps8Nms5u6^x$Jb21%#8%^cMGi2KNKJD%DTptcy5v)&q67 z%#!t{TSVu3OUI|j92BzqVsA+5Xm%gO@avXWpV8{ZFo;n~{G)yuO+>+#Yclk3S;aDx zWhiI@#n-k$HE4=UF}tj%(L&iC5=0sOoY}-ZU3K6>MFmWt54*+tYCNbz<6As zPYE$SWb@ro-xE9&YW#>Q}fqc@pw>FmO4G1%R>Z8e@IRj0(f)%b+$SBUHp zHJ@&%)MYaU3^&yIDoCcdPb{U>;?2xbh6yw4(OHZ2%GP=}Bcrl((z(X}uV-5A5>E3< znUZA(_JTaU3GGxN?Q3D{T87+)%M1N5YXA@Wxz0GtHAIt>ZN!dJ$rGF|FGhAMa61ty ze?66j9$go9--8eXDIqOSEeu`EvUeydz7)w z7+d!EAWi-IwM3Ds0XAKh)-q$uNYp=1puwP;h}d@vS1(v5Xss#GP0*j8N`lj)t>)+~PH-+vfl?-%|5CqA@-_o{X6cnF@Mf-6!-Li$Pw))B62<3%xir2rnm>h%&8ygCJ9_{UDk26BalA5xU)-0F=+ha?apgJJC+zkhU$EJ0Nq zLJR8L8f+i*`_=Si5-4odsW8n;=M-4xIDyVt7q*fsy4>2o$2d+Xm;LrPcoYc;B!FY& zOr=R#5+U{)S3pa`ZB8vfc{YU!2DmERW2tUM+(QdH;+|s&ntzt1LFtRnKFJEdruw z@Gn=iPEF?u6D$sUUsgKA8aaC#avDLk-LKH0=J69hRH))(9k?JO>sA*J1WN)=vl{5k zN?%w|felR-{l5dGXoCVgh5*T^X%=tpfglTkf;uMNk}bPaTkp(aRo-Z^iti{?G?Nc8 zTN395oone~`MRBL%FKgrcqWrPo1r?89^iTqYs!W~oM5*i@^Z__ct?kZY_|;NT7zdR z2Yb}7EpT|cCjhZSN(JKju8gpbR%mLiV3j@nAj!9TjvmJYY553h$Ij(|=Vfp%Bc_>I zo;RDqel_Q2o4`uZ&vyyfkl>vY9k8SL#RS*_Ze@#}TXe-5C);CGlSbe|t)e?;3nhy= z@*?W;bI5zGbo=JjWw$zjX>veGjiv0jLib$|Ll8SIdKpX+DzR?mUG01WoF|MSeIdo6 z0HG}+Uugt+P2S{m2x}g`j)9<(C}yJNHalH3nh--RFh#BEvkIfw4$$WP7i!dofO9lOd=7B=<){P=1ZEIE9QUs;p;Q$(-3H-<~56wDuPc9nhz`7?jxcl z@yK%QIe=Trn`$=|2@v1ar7Ew*JWj4&XYlg?w!G_Zu$j63TjAYzP}AMP#`1Q+=VB-H z6Vzg^cY|jEQ|!+g8h}4X(9z3j=6(^qww#@UI5Y52TsPR4Yzb%4t*HOlb_zFNo%#dV zt6{YmV4Cm6?Y|~wtBtvKipdB`=hGKIMw5CrM$20J9NNXUUG!34^LEaY*+il)4*}9(E zyL9EVt?zs2RkcF#GZeKOH!}|G>ANmVv!ZnWfx4b zQ9wVhyS;;?f5?f5IlQ11-hML3F<2)jC$<(5`Opszn%a^AYQv+T$YH{tQ3iB&Zf_nd z#^plI@_&&$I|qfWWLSYWCCYHu1>;!-(zzY37DA$h(tW$A&wQUx?QMr>9pB64qtIc@ z*1=IX3f;~Z+ynUUd0o>Boo6oCA>N@69MF!BSNK*Be4U{|L{)3rMAOlK+?Z8T1UjNN z-L5JXt~FPw9-&0-+_{R`D@`w*Se5*#C^xRn+UUJmQ1(DpwmsqKm=LZIHqiQuMEv`S z=u2v{*ORTP^Y7)0hoJP1_{TWb0x43e!zvs#z6!kr5B%_}BA!lxjfhGHg)kN1d@SH; z06>6mcpAbyMLq2=n+IUKsueup&r(za_i=aBV^F!4P%|Nmuqf~x1pi(2Ly;B?4BY~} z{MK{+&67?teVnI*-5StKfca5}*<68*EmA$Ku?>Jt5cKd7ab3)q;OQqV+t0bM0nww> zma<9n%;`2WV%g{!9}!1ULxpv85E;%8qa$)#_`dK`c}+A_f(=z+_6cW?0VO3C$mC<@ z>j5n=G$M94*Np$Ck;@F8oE0{>u?d&W|4A1*}wpe-k&|DO8IP6lN=RG z&GY`N?kn|@2VZU9+7ZJvqmn}vEb}90No8aWuf+8y$S_1$|HicNHN`b=x&3o}c@WOi zHq&PGY^&dT5^cAJfEZ{(sw(-^{F*sG{boWPcKQZSjjrLcuQ%fXcDO) zeqg1Wc!dNdlRW(TQ%l*Vk*aeOl9jD{lh_1A9+E5I+jBlv=f*V*h-WYFU1m<3kp|fP zK{}&ym%W64e52{%$3%gXc8*hLiRDf-N<{$3k$Sy;4wpqZ)P`4>OO0M${ImUg5|PF0 zr2hfv*wZ4^CNi zsxcd0|4M~=eg^6*k#(#dPqq!gcv2Cwa6P5$MmB4AjZB*hKqcc z{)}^Pu;kpVwn?ldguAOI$39;v`CoJ#KzD|-?E#|m-pt|v^gyGHy8U%Y6rJv$MbBTO zJf-DEFohz`rHYEZyZIt-lb+nF0MXA}MUv)J@w(r@O{b!bdf>>X%XLV(c3y6&jwx-? z`QhDjkeRzOtoe_bY7X*H6uQRXuvrdnGpc{FtXFFMl9< zQv#HY0VWTYDk*n5dkIk4sCj|h16!@22Q$W}CvK(A5Q{>Rw@(BaM7O+N!YuP;-gCH09$xepHi8Wvd4j|I>c?2+tjg(7=;hGC_&66=FxU1pCyU~AJbHl*+ z;Jzv+SPgXavyLnt5M1kfkQHV>a}HqMw#nvatY4yQKuBnG|B5bvEM$bbme2A(-}TXJ zb4|f;Z&}xKyOT(iT%1MOfk#jNCO|*))QSC+uO7;Aep!uk$#i?m>%6C@4}QytuYIH< zViiy5(yCOtf9}nTVPb2J0)LjiWqr6-M_-aAE3E_ax!5qpfNKYdwQvh!s&c4I|EONf zN7WE{|ABEu0({%BNz?7idelK;`ZB+B^8lAGRcj%c%`VHYv(->1c&X$T!MVmWgxY>2HJ?woUp6cu z^Jo2Of%8OxfiM-Y(@&&8ya)bsnsuQ9lkG7yA!tosx)YHDt{RQ9G5-*L*9wnq6jw>V zob@9<=8#pfvsK8JMk6Ot7C5xm5)2ye7QJRS)|7$A7SJF>uX5A3jxd!93$N^|dN>DD2SQ9$Dk1;2%P&y60wN^<3i1l|$a5Lr*$j=%zm>YKn*(^P8&Q7> z-`O*Bf~!*tJsBrk!<3q>0=567P@V-m;tBExrJ^fz1JC0OibS@t;#d4b92SwuljT?) zv}+d$MWxZ%yiai)rZj+eo1*sBsQ51$G4F`(S8W*Q(_5o4k2x(Od5gFX{I%Itq#Y7T zVb$%eM+o-CzmyUP&Oe`GhgcZ>KD{W_X8uj`YR@{ctG~JRoDYJ{9xMunG)Z)l&q=uu0X>f)@i{W`y0!plc`8 zwWsBBfT!s%Ud{FrlR&OhqW)WP(IJyY#^!u3i(4-doVc!1aA`{uhR+vvGX3NfO1g6T zKK@L@RJpuBbQ`u`nT{9 zcsL~-5gU1>idS3q0_^rAF$=Nd>f79sJ9&~Ti2DzfhKUi@{KD?@MR-Dbk~3OW|6;&+ z8~?BSoC+K!x|y0#fTqDJ@uIQlH5%_jPouaghe+mY*149(gTz>)H6EIb;zR#pAdbhPnZTX~3H^UyVRAglDCscu46`x41XA;!)={v@gbDXb zsv5{A(-?mx6}BvH0>OPRaI946dB^>_*M&=Ckz>s$pWUTmI>F)UdtRGcy@~`!<_{_*kzt$cM5(Ph1|# z4=w9Q%gwcE1LOer9Y;Vc?p<0lHC_a(Dh+4!;PLKU6iu(o^)SPlnpcf%-q0dEmsy6 zbCQW&u}`6Q0c`7dQW64^s+k3RIrb!Wi;tI2%rJI~opn>xq~p<5w)Q8;EUc15DkV{R z65UX>Aq8$L8UrH70X}e5W<@mcw-n@4o)h}e?eeh!+ia-^p8xj5(8yj6Q#TSg1yUKI z%sx9}xD?7T$k@1Ow9F(b8-8Q1$gS@yegbltJ43Z~HBX)*+ZcP5MGIniEkBA4cb6d# zd#9@RW%pH4dsGkaXCRzHm5FH2w0_A;2y$H(?`)D^8Wpm}o98hdwIu>VG+%;^H%0~y zyvSSWxxjG=g4ZOQ`WQaw@cYnn-F!hz3$AjU1;*Tf6{4M8Oy?yM)({wlT7@%=LKdoF>r(~a#2slrvQpg4% zxXJ&FMYgbGXmckRpRcvRpwitLi_ELWcvK8I?q7ZQpEvdv*2*4%WmH=@$O}un@e>9T zfVx6-n?)TRYk6Deqz8QM@wkG=Fw8rr#v<`-=bsAXeLo7@Nl2{?_n*Bh(^x8&>$nW| zB%W{D0^O^$>KFUkho^}453uekMEJ}==Gzj%&T&O^zpU}|)rKv~<|ghJ>CE|yN@`iK4I1aU6-~Wl1qXaxLCZGkO*VKA z{vp|y=+gc>?yI@DkLAjRRh$>%GZIO-hUBms0WUgSxbvDb++FVioZvbP$B3Cb53-R- zS~l0&iX@uTxOzaDu8JXl=_c2Zm8n(sQktS1ob`=ksq_nBP3ue-Q%2{WXs(@ zHtH0WR>kW(ad!{}eLSMFwOv49?K=2$wlmHfSp0>4gUxcD!4 zSctlMoz`pk7nc=iPkz)j&1?tXz38Loq(x0@P1oC$KAq}FlMrjL+msLKt74t?DxC!k zE`Z%T2$*U&^0o2ZN%h~OH-ET{!1d_;@w4}Gl=Lo;hk46t4B)NL2@vPunV1(xtXP-J zY{0!KP5d+~g{FT2J~Zn7p-#b5bb1rw9N~HdAkEvcQIHt^3|6d$0D&tolOJF|aA&xD zWpmwbTlD3Q+Z1NTj&~w8tSh&wf58Cx; z#w-)pSwbk6CzB@b4-g)OCF@6NgMQ~Lm{%lImY|G}c zrRi;m>uSe9NjXl`#j_#t)5DOf_(uR8d%ouhXR!|iP#RY^b>6kskEm70 z`Q(~5GiYx_Hr}Zkm;N^_5k<*9R${=NpNW#{flEvdaQU$CxLcB6uB)IM=Ek0zc1DWT z?2Mlz+Lawo7Xk3O@GGh2ECs)d@;2J70i&l`dK-hIftpyN07WKLy93c)6@sbo7IF%euPBSPf%~Ld9PN@Jzh?F zWNE<%$*;H!UdA)61oJt&tcuiiDU6ys0}&E3>=o$f$Yo(K_p1>1TE%E6y16J z=c600a5{K-6F3T()9%{(oh)Za{Ccv{uYi&U_OCW=dtF!3b%Ae)oi4=0iJ<=X_P!#S zH`a)&=@s4T0O*0%@)HEeuDxAkAq5E1zrJfJhc{5v67jl{F{BAaj`&z_Mst)(h46eti$d-{td)5!|-SkjJHw_gfH>Sv+ zWV>r%j_5sBEH;RVwcJud(EGEi=;=27ul;l6$Qz}~A%{q{<j{(IDB zf?g}V`S5_Lwi({vR=)2)!KviCT{z|%!I~$dI|zh^<3v5#v50+P?|5CZXN|yiMsS_g=BhB7m56R5SyNPG6X2LCdsNX*xQnDW2P*C zKDYH#X!uC*cOM&?8UTPGZ(V6Sm|n`|(7<@J4TfpmMrYWFL$*0SY@5*?spE?6c)We# zc)sTq6C-eKQ)H~#DLoX*GXQD8fhdQ z*{p9yHB@EYFs+mwXiMU9f%4&NRf!79iI9t#-z>qtg5Zx$K670*n(VIH`#MDIa)8vn z>aK-biSzr1w270tAJ;X}S(5uwjXzUK2PBQ5CkCWaH_A=XW4ponbLglRN7ZIDVo~t= zH6bY?0HOWMhH@WT?ePA_=ua#Zr^GcBhQ?xN$S4kjx&Q2vOo9KNASANJs?0g=C^KS= z+6Z3#Pu3g2M~HSli^?pHEpMw2yvhS3c#?tfMEUr55G$bTnoojxe#9<7`5?rK{)*u# zQBu$CNzW)3(K)|%4j(VVDenS(`A+?3QB=aqb<=!UIFH!ErA+#q1NE8t6t|ged<>1bD*eaxHWIAzkU~;s< zObVKUrFb<`Xlz9OW4o_lUoWpD+9#)jg=s67+Ssz^{K?I(4ix9zonloV$K^4XyKbwz z{GOzhIvo^Ea?u(LrA0#h5FH>Oya|-Dn0A@##s?543;`fV!_%Dx62N@x^==HXAP3rw zE97|IWmmPS1}8LVD7Gtp1|O=KcCbj4g7DD_K{B=CcL%--eBf#|R??JklvGzg^ds+2 z1lK}S9X!W|T~Qh!q|9$%pX?pZ>*M^zw;=IRMfB4|mZ$Y|jcn+@Ue!EbXI-i=eh+&x z^%(;M610u4;zCCG9q1;iCY}KO1I6js+tIY z=40+$!n={6LFr+vthuhtj^#AsDA$LMC_DTEuJ9M5L!7;#&LgellKKr5d3e2NUF^D? zGNrNC%0ZinvzuOLGe>^^W^Azgsdrr15LT|zswa|OJJSO++7cg?T2HbTDg+_#Q~Qc_ zio1vtMYrr~K11}0NOfvHSY1#8d<0|_hNXYqL4X#iwC0xz~R2nwk=3?w5Pg(pe(W3D$I^Ipjasaf<&)P*ol1O zcf(`rd+N8{?pPK!FB$PKIPOd$Z;iTBIOJi8gJCY)K}aAK-#@R5_J960pMkcLVG&zC zt0A}S$+ZMob6Fwf z(U-cL3Y{fgul*=nlInbPY%KS%t|X0QE;>KXE_gHcL7P&-*Dg*IN0(C+T~2Lww5n@a zY?S{JXmDwI52lDPnz{=ctAok=40)B2b}gfWF1YT&mYvd@UkH7{eEX=p)k>X5lqC@~tkMz$yxG5@n8F<|M!w(r)lBIP8k%v_SM)MPxATwdE|qfX_Fvhki7DJcDoWQ4pUKowhpb7 zS+ikQ*oU(J>GcsMF>#!0)L2SIy_Pcw2(0or|YW2*P%6F&Mu(hW^jIuaCMbAVBos=dMEG1v*}MOh5vPr2%t^n$weh*H3476 z&{S-7x>v5(;wG<3IRfYh|E>Byb<<52*M4!;IN^1R{ZN^3(5*xl&-87I!ZAAi_&F&y zMY_i+q42&4Ec`}SbeaIjvw1+SDR`RCq(e5$!sAYfkRP}rxrpz46o=Q_2*2NR=G(Rl zvc1g`qwSHfvxEMiI744PZ6EheYV!*l8vC^vZUOZl+DQM{iggg?WWN-37oK+``$)6d zB;iAXAk2jX&d7(wM6wE>a6nej^yJ(;dU4kO!}ql|t)NHB^!@`}rXC65sIfW!gt5Gu zD)4y%-Jhf#8+(^&O|&8aWfx%NZB-h!1je|e0awHd8(>`y-EZHVeuRsCe&9A~7m+JT zK{eXE-OM%`(S3AcJq#5;&5%fsO~lTxwd0(oj{2GRMdm(Wf73VGuvKo@W#FM+9x16h z_12XKD*edXt3)O+Qii{0iy#Z5=l#9l<3}lRKI;RTr6@q<2;u7QU+LKGV=TNL4cI^K z`ngIQ@`If-g#klAb-Uf@xxwsy0cz=l7cDTbaDgGJKiDD%f;kIYh{tj?6ISo_Ko z8pUixZci zuJvmPx3;lSO)$*&rH0{Y_dA@6{J-SdS*1i6C>}?97IPaDsP#(RCC6DAd4WtU-KyTP^20 z6?k$l&|mtm_De)(=~8hCQ#1UpBZ0TeyfQ1Tdmf7X`krxA9jeJyM{=TGf%)YerSUVC z=b`2;{$Ra#Q8Yk&4$F&xuI1FfJUozq?BjHS3*EEz=^r<%eiVyXRY(YaT5RI()+Yi` z@`ED!=VR@( zkqsUp>iOpy(tSKf^6tq+RG93j>2Nxuk%n(KEF@O76w#Z{xJ0cT@c+@~^~%TZp#Vxvrq-;9v|5q6uHEJWJJ8j2iWrnv5Zb-b{tG$e_@zt6%(Rx1CVF zq7}e;y`?STaBH@UO-z1K5c+kWaP--~LK}q@C(But)YL=m-##}Vivw(Vbtsu{>iUzM z3zV1BQt{jGhKUqRG2sb%wgE?}MK4hd5;^Gvx;mB~L<@i1_e689;~CVIx~I2Ph>J?4 zde^>b0~6bq&2<*XGyux952DM z5gpBPANoK9po|M+AlzJX4kTUli*9jy zxad6*)@jhC)V~Cb=dDic*^d9Pm}_hIj1oSSGGwwwWoL7P270;DCvtP3CWSMk$ja(L z)7iNb+6ZVsZFcE7nK(3t1_Bp8qGRY>iEh84GKsYWPc4AoqrELMA8LObF`+MF>Bx}W zkrDXmrutuG(-4I#IDoc*{ZZ<*)!k@piz7)qS^lOZOHe zC*p)1m}BupXypw?>BaYx7BspR(?T~=b(9?RTjf1TR{fTUVxK+l#6+Ecm)iPUvn^#E z(bArP<}@_XC^58-&p5#0X4Fz7`6WBRBE`v2Un`KYbl&5tu$lY5M6C%EYUw>VM4CTa zBJM6)RnXqki5(V~pI{{s?E^VI6Q%n*4USuseCMsoId=@kk z6GHeDarvX*z(PiSO@mhNCA68+qI&&?M~!ZvXxIlP(Xx>HHew!JE%z8?a$xu;*V!lT z2fJjeUHhe137W>+w4b=$t<%#cT!m5$x#wtRdl>-g?(ja3M8_nRH)OY?W=OAkSw8m+6%!;jZ z7t7|^cjI)(N{EN~T)BOD@J8tu9m5(*Km_cb(&8rSNVZiQ&CRH?osiV|;LG{wi0yA*_(MBqahTDaa@ZHSWWaI)L_gIWKi&CY(Br?xO9P z6`8(0IH-b!imHv8^;L#bgrGOjSVn#VzbJ!--A0F*VI?Sj<02f&|}c|${4xp=4#W@ z+q=I}z75|pY!5pTmt=xY{ixk7{(BuyF87Weh7pi>aFyH2Lo+xC@)3Iv^HB7DMCrkR zIpy}_u>&?$pyD()(cd04q6zMee1Mzl?p3`%0-^&oc{3D;Op^ev7mz3?rd_AyJEK#U zuIA&uynmBP#QvhVvXM`Jl#2Wpo?Z*qA49-*6R+sN%|x0hHRuIm^q!(5!&=?+E zp%D5xR#m-Y0F8O;?=t$?#vYXOkupSNrTeFTvnwr$T@ae_YgM40Iq7m%W_6egYr8#G zHuC;*G5un`^2c(~yOpdrx1B0KiK{%AMOj#xoLPx^+lHf*-^3P|#?vf`h5LW> zB5G8E62pCRl@7%dKeqX!^H*@@Oq^{JuwhIMSGA~xf_NTnB?j93pOC%PYJAk z1w=s#j?^C*)8!8c5hur9j&7yZXzI z!ygGH9>{|R@0v02Kv9-s0A>dLpFd$W`AI#3UMM}XnBcy~LJa}zaT?HhiW-b>FMw)@ z0|;tTA7MsqR59SvwWojJO`1Nt7Wr8-Kw1ohptlH&X$Jw$gP?ZZM1Jtmy2LX`uTi9L zZqqIp_j4}T;)O+8j%%|hdEDHuNYqYugh*tHy|+`xQ!%bZAr$w#&eV|zWHhwFHPj{L zQ~N(ieSM@CfEXSIBKfTx>v}xbjPRwiv08l5vZj>FhA2@Nm!JUgf#Dc~Xlw69b0{*cbBsgdW2eHD zUTuC32g^pV1ZKt}STrRdAu#|=0BL3`_&Yv*M=4PmLE=^?bKol=;7D&_owk2dT|Cd~ zMmi98KazmXk|_x>ehI%DoIdXmDWN6|u;ySfds)ZZl&@!iLI6|&Jo2fJm z-Mv9#(+ktvSKr6oNG~yO^5<;oM-d|7Ey|Vs0Dazmj zDq7RbAy}El%?n4qqGlw&#}&Ye-$);-Di8vuA-lQ*kQmqDIgob^q8S-%1u=rA?wcMN zPH+HJ`hnsIb&`vd)L(8L25ga)&vs>_6-ZLEHDZ!H^K^1hqPeaBQI-tf<|M_tn6yrI z>S#uUc|+Zr`z*U^@Pr4T{V-(E+KQ$`#o*OWIx9B0U`jY0F zd8xo!n58k6pElp|X@z(?)ul_txuEsKBlovrkm;rP(XT53-Ga4Wm$rO?>yfGcPLm@_ zYwR}3*ZG2@> zpBk1+vyt!;Z=G?pN+@Tmpez#_|7xG4_$R&7rQ#sK&-j!Pn54wNj{2(B=5qG}XFaWm zQ_d8J#awv~;D!fGxjqr~jD-ytLJD*w0i`W2Qv!WOXQD4HW(jd`bAsmRve_od&Z_v0 zF#hr0UFbia4BdG1z&9hP{76`6-A9ML^DP9H-_m9_^5yqU?)e=JDshQQ{2xY`OFQea z_sy;k7`ccH0jr!5+VuKNMp|t8sHX4cS>@c(5n5sY*!}URLN(}*{_6-0^jHAUKweKh z8FwSwK#D$A=3_x%q*|-s*3))vTKQYv@%4AI?>64)#E54rcb6C84$gL5Jr%6~LkXk83lXSx7&0KP8-at|we@TaE=dgri>f^g( zDnm@ls^y0G6!0%B;J8&~9|Ha4HkE!Vyj)j5-*SsoDNzT4rqdI96p0K>-Pr`X2v?m{ zN-Z9^*%DE2~*@B zr;`0-C$!R#f45}(H1Jw)YgcGvkX5VdOV0~CJh!timuWs#Mehf>u2OcSh>Qr2IfRIH z3~dkvFy~!aL6An>Ef@lq{sja*tr9PM36t)H$h5K&^t$PGJrjStIyh#QM$PjE{xl~) z!x*!aQHK;M|80U{pMEnO{&tKe`s+b_?L{mYwXlRv49Jz~bi0~|l?9)(8m~?Ve1Xto zKx!eU=7fn=W-(;!rM)#SzrrZ9TlOv;)I9)MCOJJZK1O)N-@v0i0R(ato4=7-VwzeS z^il&Su@_haKaje95k~fQvTd)yThM`P=Va%;Ty4(&_*=k@`6b%MF#+m^k7yH7{;P8x z+ydikZ!jqhgww1^qhLC1hAmVB`CP*Zj_YMXkrM zc&yQB>ho-KQSQv{o# zOWTMrciQ=YpvtcrLC&B{QIBFp^DLtWCCTUUS5G$PU;Kb~!(!9$Vpr0* z%{UJIZKR3ed45)T=HmNemru!<(sbFK_gfGq+pOR$=RRM`zDU~^f3I>U(lIWoZp~+N zq|CGJ+L;Puub1jk@jgTwDMuHe>RhGvp})#NeemD~kYB0FdD=@F>v&(rf!n7-A3klMq6f6I&i%-3FUSriKikgA!ZmP`~Z$^r7A% zd9aL)@fhQTi3yUDiCIAh;rmx|utYE5KmT*te^ogr`je*8$SM|no%6gXm5NQC=$o8C zibNM?Vea4eCq1}SP02&v(q@{Ua7__wQFmaPrf(;O7-~UJq+a0yJoI_)2z;;w_cQW} z)XEO`JU-IJL~1n53EVuY#_zSoQFh;af71a$EQ`*{qmRn6gMQ03{z$F(Q*LVDv(+BG z`UE!Swh&rdy{o^3tJ&T2uy4A?Y7Eol=~rb?*%{y8p1`d!Us!>3fV2B!D*qL0hgFy^p?lWt zQaJU&mY9KisS3(^87pTd@j|BW(aX8zOiQ0>6FG-y+zDn01MdIBvSj&h zGu7UTkX(2P$cd*k*`8*|;UbpBTrW@b95|4+Qkh_KZ(m}JA>n(}a?MQX)OIRtv3yPB z`3ONVqZ@e%PqG`tJ&b>yXdwB-kuO5MU3pAY8AC}CW3`HF#a6opwR9W>IhoKQr(iXWLJlXb(e-tLzgZ^(SHrv|P%Y>cPli9<`Z(#TeT$ zTkhoJzL#%TzXZ5pZy=FM^RzM7zXOi8o-H>$ zhEdmKwMP+~1-=9x~) z(8)-6@RS@^klWShY>4`zX)lcZg707VA-2-5QKo)V!!RIm(wjVPmiM^N)L}$XBO=4? z4__=EoSO~IFfih^fKHF#@_ki%y#MM$C5$LG2wvg4-4V zFF?@0=?5;6wy*@y^q~?VSx|Mi+IXw`Zwq@0V&_4w!d$M$6nzbm`mTD4+GDn5Uv?J| zz?YY>h$S){490fO%sbPG^+C+tm+yoaN5gdGeHu)6;`GhFJFd|SQ=ipBwovfWTQDC+ zfDO((+oFqU%%oLcLn(52Tg?MW3ktl=3A(3_&I)PHmgjIZ1@}tPw}8QZeYXopo^G-b zp#R;R7Zrv7U*ovn`?;;fOjhZC`bh^ISm^76VWQ7mBm+`xX($&G8oPMTC0BLCuQNiL zFO=_GK@YL;O(^z~j>pA+07;&@A}&9t)@0Yi2pgAj1(%=d_}|V|uu{-RUc(*h(A2WKR?GNsrt>uQ8@kvh@sx4C`udFt$`l*cKb&-UNccx-&0&po&`%CS)8t zj%ZF>c%L?!cdWc^=pz2HoA~Vmqka67y?)DSkBqBZHmX=6ujlZc%FUY}_WJ+~%W)7{ zge>(}Zu-vk8S=b}n~{kH2!M+%c=`sSAIzcHLBk-11D1<1 z%p{cl{C@Q8v~UzIhz{@N6Pjj8le?}^b-s6Z;$S8R3Sn0do?>WG`ifq^$)a4MQ$~Y` z-(a5H)Vw!You|G_AC}Joe(z1g*Ct(^I8B3=Dc;}R)cs_GZ%{$Q2^8I7%U}!78u}8vz3)BIq`+a~ zNQ0@Pgu+03vhr?Vr=7GpK$QmC(EGz$-skKu%TE=>WWO!?_>_P3Bk_=g_k~0gn^{8v zv;16PP>SNsY)c7FKF&!}=Tsc#2V%41PMH8~GfzRy81Ga!=i?6f9`}IKxsw#E@$*>F z9Xqd_RWm#GPve#nMl9BumEgn6ksD}Q}qKmDH6eYxanQJTaJzv?) zx>jMk2FyQ~YfTXC$j&<(RG$kTcWUPrD4S_E8)~7>oI`5K6BX0K+XB{&zn>H<#X(1a zH{*EL{5ZMao-11QP{Dr0qf1>^=G|^JCncGwoOVH~F|A0vcIo$wO5>S%`(50zUqIPl?*yU?+qE4vpIpoCp`E9->)CDnik`REEw4YYa$P5ZyNn;g6bDk ztxpaB0l@I^bwYW8ckDQraE|Y(%&Il{z;*j`Ot0KTBK1;kv&X?CU1G4SILz_PMDX?Z z#5`JQLo`U7rsb`^dnqw4DD;=!q8J)h0s6?)49BK=K8AbmeQTOh#a=b77t_K?1$t?^ zW;N=PAk2V-z%3F*r=$cJd5;mP@+Qpecd1apyM`9E2&& z%GzJ_);@m$WAuwC=F3EJdJG*Zmv&mdf4L;Q29RcIX=C|oUC6yw430s_mRzcnJb%~d zwooERw}}8sd7E_8XmGU4Plj$1otC++eS?3Y!O5f7f2tjPN5 z15rY(aCKB^rUvS)JaQ%K4@2x7N6KHhPd0itT)19kZSlX350dCLOxY_WXU*F(GBX-(iR_)+x~f(;34Xg^%6cDrh!6|FN#>od-J;RG z0m?e&KYk*687mr6uVEaLEbhjkOcE-lY)KrpJ>D}ad(2wdPRjBRX=9wf~-ZlS?K=xuznD*m+sxv}px!-tdm zux7_WuN+gsFlHkDg4$KTo!fg(Se8TP_xz#^2|=_#=U+T(ga^PxGSdy6t?< z3l+W7&*!iI&?J|1=0rzKhn(XpbjAE}VN5>rj(K!BB)1@*5ix`bCs&w>KPoTBJjPpx z>9awW@t_6aN6~;DZG?}78O80nKVNC^WHho?ra0FPee>ggF(O_mpBFvE@y`&5Z%^!f zlDyHL_~cxDSwci&gK1vabTp?N*ZGLu6#t9L9){BXeE%Uvd2a!~gZ;~Zqc*E&YY;wQ zd4XTP3)v^ohu(Kj(6anCf$-zvFiFPx4i=^bM%&D5wPludjce5^H{`R2^Hai7dNYQR=9K1#P8D;{_; z$GbLc0_LcVIZl=UkE=Tt~{*{dX#X+~gMi3BZ?FH;8K<>C3)yTf`u!0b$Cn zTe@xWAC(~rEu4={;j$-$zozUTjNjTHDEG9*ZsP~SU~Q{@S0?wvM91g)L>Fip|8r9( ziQZEKFJ?muM;+*YcXGkivd38GMp;io2+@`~w9so8H##WdQKV5mvAw#ILGF}(6{@4T zA*}I)VF}d|K=J7g5G~VGR}(SX3m944r<&f4FcIUUr5o+4ty>R^c)U*j$guc4@VK#R z2MO&=pZMa?onz`NPsazyoPr?JQAGVp9dpfZ=mUk}cJ55~8pq4C+q9(&{t_Gksy@Ch z9T6}=MPIK@c=gV6YQQAPvyZEG*3APvYh4kCAEe-$@;)(hht>V@rx6MMl=fU*TGm1% z28U8c96s0QS(vAk1|*g#UnMF9*Gg@cr;x5kN^Oqy8!;?i8Y&A`1lRX3YBo2jJUN?r zg@6dBYvynUjlG>R2hI`WvnGeTgAY1Jlj07!EO#vRsm{9!h(jH4e|vJ>?0$^dZ-G0p znD1_o|BfloJ-^FRrgu7ro}7vDK)W7`*oYrs8^O|z8Vi1{9!7r5og!W^ER1|Vxp|PS zCgz21f>=;#+Ta_f$bIaW4~0lOuo~ ze)Gzb>rfysAcKruP(P4lIQ}&pceuWT{B1oGwCGzN1^jSbLAQbD`#P*uk3Y=&+n*yZ zIX#C_xnSU3s@Hb-(=&kRn5f^5`vMG}9@@mCFH;c`&|9bcb0F*4fZf3gHPI~ z8#Z5u2)bgB7QLzXlVb&y00-5PM}b98zJq0>vu>b>a>4`M+$|KL>}0!{-6RTHFR-iI z@&PTuws+#Mjj{^U((9pOS|p78SfS!xCF3~Y70Wygb;Vw&wDQE=cW9~IS0`HbEQQpBX&ZG0gw3#Yoa$&LsU zv<#i9Roy{%1l$o&>@fW+1$gKNX;lF8CGZAyLoy1}BrXlfy8cuY1Z+|GJ_9#F%XR#f z+Dz)#cp|ww@vGigAXPhw)lD5tX}ISu)LHBhHl&Qo9`k?${;UY)r1LHx1n+6r|mjE53{ zgO`M1f_|BnycH<$AxHfZ8&)j2Vn!0hkqM&Abu87zzWn= z#Eq<-`C$@}i~wvS#MsP%RVIU}H+tOgjm`iz2^=$O`LA!eMv-gt6ttQW+?x_Oe~9)- zL`KNH85)q!a+5-5M9r7T23)tZxf6mi?#3yhOCuA%$^#()bGs0S| zO$X-X){dBpgYnCkz(h@=9wFb@nDX1C}p&U z&T!}F$7tik2IPSsZ^xyXX$1|j8M>+~+%c~H_pL7n#XdD^{|W5T?KVUN*jFFf)}3w`Kw zSw-_!;8ANQ5@l~2A0iuSes<3OWLfCnR&vtFyw~ZmdHvHMv18HE8s(arCBn{#`+*npAdB9tydrS>c$NmwM!s)KZ2r@ z!Sc*855Pt8Qhv6U$sgZ`du=+Yc+MHwOUafMk`L^cTlC~>dq}u4Zrs=OIB+uetSx>) zb1r~5u%Q%0>oc(K+4fp1QcP&FUTX+YoiEYXGAvm5ts>QwYpZ$%Fa)ju%($xgMMFG2 zstQ+0w|xmAx4Fv`&=I4&l@%KhMdeEVpUx^?BDKE`^f&io=Dt#u-zvIc= zVwiH{2B5!&bKgi0NwvuBLK^vKGfyQ}^k6O;K?`>BuEeHuEkUk$Bb|tlN$5Lm^Jdhf z8-J>luO^g32u%V*pvSbeW8X#)kTc-jOG0!|U(X56GVV$W(GyRoL))~Nw2GH#qjge? z^|vM~E&fuGTSw%lrt)7z6-QF8TR`aSXF!qems%(OpC{E3istuCaKoq}!1HBIlym%2 zgY>gYx}bPoA0#X6<=%tCS~A!SB*tl}41n<(>catWWECbL1MqtMG=aws98}5}s80KPqM{ zjSRH~*@;L6s!Er~$ZtQiMW}pB97_9Zok7@jlFsb1mb@_UNeiI^xVpu;2#XOj;363T z)^oxvl7AZo9#~G&PNQ!H1CY2Ide{DGQDNT>O(x-8*B=In8&_>fA`QCxlOv z_BlB9adddSwkDTl0RD9cZYM2rn5u@o;~cMs5#5xy;rbt$brz$v;2~C-S|qAcMxQwV zSc0#$-d8iThYhq`U+xol7MUE~vJi`xMNq!xrd7lqu~Mau3Br-7qmR-6pgLNn8#@p4 zzLCk!bp+VmBt;%@Uak1h*5yGO3kC6AC<)(38jsvj)&xTrC|E(4#3kIvC@{Vh3RufCHlXSMg8+oAVI$_p(FF)JzOvRMfDAZjI)6iDWn4 zRgG)e{2M3rP7kV>z=B0momgyp`)U2l~_Xlvv&kdD0xUrU_IaJiLTUkY9hA||D! z)6tG?L(6V-fWbDqwL6{0$^3MgC}x2RO?9)+De30YFH6d$8ZlI`@C=rhXm`zRglWk{ zgAfv|Hpeykq3}dYtuleCysn?BLbdG~q^v0poe6l1Te~#GBfkR^7+ru-=nqjTfZNRC zG+Oo{j(tQNDYw^xZ=zs8yTr)8gX7A9D|h@~WAwG^Yv`*K?*8R)9xw=}=}Q^QS@jZN zo`q#5)bEVQ5ORTIBAVsarBN~^IEsyaG0O#x8cjqqYTAz1(d41r?}M>U)m}F3irnXeE8T9O%kS2J_`uw-CWYaJ8C}`f}PP*<@J_jK(@vJqU@IR z3qGFfq`fIb@h3L+C<#cL7>QDza+vu9GLF?of`%(_=?DGg)3A;Is4sW|OIEh0jw0T= z^5Dn4d-hbHN4KE*M*d96d4je6m5z7llAHwh$p4IL^VSMj5^;=@V%N3wV8Sp@?0KvB zFxt6X94M_#F5U^$Dzvajn;h$j4VWKK0X_SgnrkIy?Cg7B=Jn1EPxzU{r>qE)Xf`uG zxgr}2>dcg+IL47vB!9^|^iiREZd@pN$y9bo6wvCccyt9m=WA#~NoBuW#kY{45wYAY zP4|=A3;iJ|fhC8{%|IUP3#$JeG)rMFCf*Bav!u z+-E}5c_NneJoAHviB59DL`w7>Gkm zCVUOcqsy^tda6IUa9$jwIskT-aoDNHeR+d8>IcH~_<@>g%NZX&QnI!H+pQ00E7veM zOY-^zN0Av5;3;5~!*8|B<&2WXuj-}oJv=uHfu?{JqQLIz@P&2Tyb8s6GzTs@jIx-D%z7Sr3c^tjKaM7vS zFY)bz#^B=iI59&k7t`LeXrQQ5pp|G|kfF`^JGlw} zU2x9l?)9bv8JY@{#Reylhsy)#b6|^2k>Wg7Jte?en|ZVCEnaP(IpWM?vF(b;-zMa1Tq{kKwYVn zM=E2S#F9vEB5NOgL}tI^}eS$x6nQWSNW6vjTt|1-Ln$QzM5}#aL-Q})+#B=r)A%#f%OOF z)rqRsPwDg2qZab-Tu}^{UiW1O4~VbhEM4YFN8Fas;dx$e+47of+w<;@Y|5PGH`#0p{_ttLcSXf#N&t?^Nj4A&*J|D=0PuP#|CVu;t$A-*AgMBrr)!a^PnJ+#~J zh&f#KI^Jhnz9QRKO=%6;5?|`$WRmZUwy{RS!XWiU z7|%99m|wuwo&2v{O$tW*FJ_J*6p(i2VGclVY%|^!`?XvO41Q6!e)^?g!*yLa^!r$< z(lhV++aJ`weTsnc$XB5l^BuiafbS}?YC%g?oBKW<7VcH8@*$} zKeFiaS`m~SdJOhAIp)J>2|h zFxc|%8uKVXq`>o(U!JrIt@RV zB9&-Oj5rtI%TEVvX0u{`yjUP>vsiU&M}XxmIZKe9%5tEx{(M|kh*-phmvW);=GFYZ zK*E?{)S4lOA|jD?M8(y5hJ2o;cda6VMXKY_SC9ZqgB)(CPH6`~#Y8X%k#GQOouLZY z+_ULmcK^>M^|-cc7Kv%d+@4&OSsl}ty8XdL*aOaujI6(bOV&_(K^949F**z41qI*X zTB+-<7s1=m`)5Pr1|QPA>;KI6EycU|=?)~a$lH6|F1!bZ*ZNlAl+%97A!_wHaOkGU zR+RA0fSrTg8#pAqNLy%xiVX46qLc{o%d8l>IV^F#luP2se7VkW9uhr0~KSeF$zMh_{0!6rnLmK97E>X;v?KyLh*Hr*dhz_LV)UZ zB~9Bqy~s!-r<27BV&N!st9)ZbZ1Ua?+;uKYhB@@fnMJr;LF=*NQ>F|;+j(zHx)Vhw!tKE!gN6mre zQOfs&T9~hp`Yo6llRB9sL@?EjZ27hI#_2l)`4G5jU4x1LRdlR<_HqLc2bO|#j7__$ zff_me7u!+c5$1HFX#HL|6Uk2fzkT7m*4+@1)zL!pug>f(t{Jp%#FvJqHa_Z>#}WfM zfvN@>2t+GqkXf_H0INdRE~P=|{NV%Wu!ZfKcI3LHia&Wie4|y(;djeK+OM%`R?Aa% z4E8%|n#vcwgOex1R^UyoXDV&yHs;t&7e6h)(9-DiQnCsL7hYt#S`{WVmg|_dGXMk9 z+)ayh3Zj-TqS<5VPY(K?-M%;b@q?%7eIWJx@Qa`HSo6MTz7WsUJDhJ8pq$)NWAM8% zZsm6^#CK`hbl`Y8lObKWp@}}*v(u(Y$al+?0}EvBw?nKKN3E&kW26Y<+?Xcv#J2}b zpJn1w{<;aNOT3pC;zH06u|)9j6OD{pe31D$a%4F8ZTv_zd5w-OS3xp3(n4⪙R# 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

PC_uX=4t?85w5*C2%+5c7T@ z?X2ZboWtRsN@6<&czmp(_{9HR?UvX=%mZh!YyX#afxIKNYQ{g`G@O7foHZ5h4!lkE1xO5_buD^OO__Kh57L3YmDxMN43f<1>rqP8sLD zRKweZx6R~NOaEqL{_!ya^iB8~H)eJ({{=Nl5$%3w!Q)#o?W=9Imf%>1>jMgDN+(jz zZCud~m5No$sN|y~E|RQ=dgxwB&CBY)e6Rq-2BQ>OLzN|Dhlr4e2y+Hl%>Pwdi|Prt z9@F_AM9;}uC5qUmKvT_}KClVbn?_{7%VRoat6{ACAq-Px5 zUg0#}9l=!+z;+LYfcbQ;nF3drNF^`^EEA0|BHJ#To}Sa3ul%p%LS`&2)PrydlIz3#o`9z@63cTFidqPONEx_$^S zOyNn@#Cg)7q6~mja>Hg~c*bLD{=d9i=Fz81{rdcW;!So@>yU!j@^9$pm`cPd_b^x9 z+H*{+Cl4%G4ZC&pBKtAG0Ud6y$VX`J_U13Y?SXkt&pc!;i6B z+iGSM@bU?aCq3Q)mnyOS@tsVn(}SwC!p3NCyW-M-wvJ++{YWRasK94`bory&t$)yX20>oW zpOYz@G>MNMOG@HlAYr-W7wZet(b^1%W25QrCzDF?UPmH58zCUzS1uQ z(4u^tgZXO=RB~OPZz|y#SXCt_Snih^Oe~r}Bj!M0tm^E8WV)1gu-dhaO%WUN!P1oA za=4nMYGW8OE=3GC3(d|4=>pWXL@dY_t%~lo$RQeS=($IXvL!-&`gvXE(!&8R8|6!W za8La+?oH`|tMNh7Ql~)N7u_*VcCqtAdB`_e%&eG9tPy1H2ie%pe>La1uDj*fE$jXbP zQ%0K6t~b_Da>UvBPUl((+qHY;XG=MzQ{8n1%({Qy-Tf|RFXL{*V8E(qp*YR!g1^VQ z7Tj%GIHgPPx-yuE-P~JYEn|(w#yL74*}yELtya6f5d7*tr<9K6h|j@@XU+|Ke;9BrvsD1UA-KXk#04P$dX_F( zG6ohl=KM|7OmwAg$zZ=B?oOkp6mL*|stNfaK2Pvy{N(BYc?alHdkA$$3h3Gsxbqsvi43^ zpA&emA9BI;*cJ2vssTwb9y%Nc*==M9^S+8Ce%&-=HO#7$a=d#CKA z^gSMR_fTd~6=^I?mX-%ql8$HFTsafL>G#>fmUGe^vNWVY`F*5yi^5eW_QgaCu>!{* zKYs&{EyUUGAJ#X|i`&QR$eX{BWAPp340yBSwkI8U?TTW6f4iO2P{JO_{!`9D&G%&w zD&(p+%=(TYY{v=M1t~7WHu7tw;_Bn`mE_?_b}Uv6{w8(>;Amc$*#M+|8n-HqiR>f?0x`$f+AoLJ=gBurjF27t8lr;bHG4mw04T9UM#To zCCzXq;(ST&NF>sbsEm_I__U?+V=6L`d zlR{Mh|POfDXbVfnX>QkwvSai`L}H!U zb#f*I`*k`^kKioWBm9z?`bdg}rcRwpbhTu}4!XfLS$-n0U|vq; zd$G8|yFNn%l1WbX5uCZn_V@bim`|LUl{3b1JhH80@serkHEjv+5`0-gEVH%h80r~) z8K4WgOh#KB)fLx!VRLgT-j!T50DV_bCq-gMDtUDqckxYYQI|!MLq+mA?Yl_c*}bV= z)m5)K5sb(rr#8Mi*CtYVns>c1BuxZrg;>L0BGr;`jV8(tUxQ@Nyk4P!*rx!#OcnZc zhRn8{l&~?x?6s&m6-i$<8MUp&N{GKzfqa0DcZwnrqjq#yKIOn)j5|9R_fJL6r8i7n zxDtjTq>L>?t3i}=GOQc?I?}eiM}0^PJf<3}|M9X4f$7xI_5HS`@m^*(HZtxQyW6Hy z%_EEaOl}R@8JUkj*}xXyEt+0B3D-1Ehp;$RIeCwDujJRs%I&tFcRiQ?{GcfsXyAJC zf!HsiBA#(kFy>;*;Jrts&#Dfa!{kyQj`*P4jdfc42i1^;IgS{|`|sv^WLy1Q9yY6X zGxDoP1+Om2VJ!;_+`?FgewT+0%tI^;14g;GwgZpEolaRDz>udkzL#BWkmLauBNAZ2KldBjwS8NU)_vGX)g3{?D5)I zY``}X_%$^WPjOFBLLwnZHZ}C70pqzfC>oIr(q-f@IxeCZ!Ugi$+oz7GdlUR#z%glP z;?MYIncMC57JG_l%^fZVXuboB+*4L#RMED=*fz`NU2Y&ky2_NE!rVd1Bk!~%!0BFa z#@UVDx}0q?r#z^jR8QI*l72kEg!IHRbb{Oc$l_vF)-dWEqIPh23J*?E&4LxLgn}mB zd|UnXj~2sRX?DkFt@i{e3)cNMJA5pq-z!G6q0hkGd+)@YgIEk$I;Vr(>m=QXT(XMF zEB{8|QlOndT#G9!aKl8b$8fqzsm18w7`$tw2Y8S^vSAW2$a>U2E#T%8n=|>r6{k=B zG8EF8MU@*5ahOy`*jm-o`Oy*QgBaxL-Ja%HAXYb(+NIoYny)?o{96QOI;NZQXlAL` zh>Y-5#JZ(+=HYz&^Nx0|XHcMuPW#aysiL+3JwU?0PLRW(G%uO#rx;d1&w4>w3h6Z? z(TZ}8ibs(!llc2+3!%0`DslI&|L2sxh*fWNe#!P!?q&675x7oX8Rd)jkQgaj!=HU|{h8^RuC$ZMT=s%@-{Ts%FVS zv{GF7QHY0rma(I_!t@gJvr&05P)9~a65_A zygD^r)1NH%k&ii!1@%7DpSva>s|IlZK&~bTcq_P_ol}nrzW=3O(I~})e^h)p7`)4Z za`#+cd$$XS9HPvB!laz6-u|SS`!jnZsp=-L%Zv}OWJh@z{t^=WBi+%aJT$YZ)xg&6 z`c1#YK@A8cDkY+~iOo{Q&SpvfnUwWp>ZPL7%3rm+tIg(Jwly0!_|kajxmD%ed_35z zR5fGxtV8=%@tMl}9M9$b* zK-%&_r0JE2OzJ36sdLM&^oJYO=r8PehhVGjt@r)|55WXqUCI1{w8}tN`uO zn&8$K^x`9_LLF@QgDt_#gQE_RhL@XYOy5zvckOm$-*YJ7xiUh>7XDACnjcs&#Ojaq zDD}jEUcP}XH(Lt8nJsGhlL(Q7o=fJ~dqL=Mn30|SJw%ClFm@}+t{%w&dCXuGR27uX ziY3ZG!dCxzNUfE2@F;|~*WZxtNANbmIL*(5J%}>1dIr4`-)Y~}RYRD-fS=9`8 z;F;R>+M$!C3p#rXYP`++6$?l!r^rRkq7uj!@qf^Nmq&3dv#Tc!G_j0&_Mse=3)FTG z7=Qa|_sB{v%u}5UzIW+XhU^xV+n;a~S_;c5804l#cElODhns#Toqk-ZH>fG%av2#$ zq5r~@9XUJfxYVP7(}S`?I-K977dps$zUnv#L<^Ja)LUt3O?Lr;ZXS{ei+2=ZM+Ua= z+G3$8;Bs-vMp5TT>IHs`QS1Jz>hN@L*~S4%HPYrb*x!NMo>Fs6-LW8tL>UgrV$=Kp z+oAK^E@N26yZ8W%HozJlWps*-|RZ@+ViLfF{flJXR!|`MW z2y6Yh?{Iag7QGd6h1InJafYcn5-JGBtO3=#$kL!j#Zve7JhsV_UK{HS*xW=u#SCb* z(yHy4Zf8~ALR3y4hU5=GH9=azG#ZQ2$=-j$wjnng{S!l5&FSj}UN2OGK2y78h@+0< zIfBkYjd6~2`E3xu9Bhr?e)w***@Gp$qAa7HShyv#3lN~`lH2yj=3PJt8kbKpUjGK9 zt|@+8v!#01cCQLQ{!b7~jQ6>fr8-+8+jx!MCnqqXzVOahX*7`fD%nl7u-~>semq86 zD%e=gox*sF=lguv+xv*-Vm=W;t~|c?NtuSoFhQhdkUeh=fb)(Pldw-aPsH2-w>Ulh zSP)C@KQm+lBawf19rmH{PXdlVT5*p2qeMxb*OKd8r|Fk?c@Z7;?qn{mgocZL$WA76GE+=={;Q=NWK+mbKztz%qRix=^ zDhtP{Wwqd6N+~}&ZfR@ecL^*R=8MGgVWTc}#1Gc*49U`+sv$?p-r_0pxhO-_zHAGW zW}Ti1K$!Uuu2pmO0Fw`5_)eBQ4ncS`r;;f`?SjtCji~m7IPFj$gWCiMt(E#%Q{fPuXs?H0f zaI#HAE-Pm46>v4!=`g{k>2Y1!9rWpRz~*aj%5)je8zWJ^0_@HQ5lO11XKS=yF?n1S z`l;^VWXM+AEZC+=(EP_4scRMrr{9Av((aw*A*+X3kY@s?Hgo081TQW0MJ8I}ooEq& zqUJqTEOIk&+?jrQ355=`6t9BdQzC1aar4=pwlQk~!FvGEfm8iUL_yW2t(fDYYfI@VHHKG6ot0J~i@mhqN`?E>8r#$ckfVd1EsOdN z_ea!zMTkYepJ{c=cUCPvzW)^8B??>cg>@3!E{AoZht9KPlJ{|!g|cZhHdXb*q#sd$ z?MkA%4$wnHX}{2T4&Mnx_bZ@`*_|4hjn4M0BaN+mM}fM=$DiWyhYeY@>gX)7LJ13e ziUGdornAQ!;r9Q{eH@Rtly8OSYi69!h@U25#+;u&tVque3I;F8tPeK_qiaK7L?nBi z+8#uD{wv1Ap@&g398+2ZL)?Ysh{ULj#BKc5tvNle7e0gtr$+5R*b_;itb6)>gVziz zswd2cLIqd5dsASLpERcyED_t88)7@X`Rd|ZM*q%O9NpCU-P6JD9tdrdFyU>x$tA{D z|BG#~W>oS^qsTJix_OBu4W$u9-tdhO4;r3^UB|=W{d3e2O)$z{=iV7q-wpD+882Lf ziQ8Cyn(?%*i_UWs0`U2 z;gU}#nJz^^X7O)gIr3TLWyrgY=-_V>{(PJ`{bQ=v9B}DIh1ki^CR}f1q)0-29h;dkhSO9IXDYSXL^lpI1I1Xe}V!uFz#e z9bBM`PWWpGB4$z<0w>=H{tX+BL=~{UKFZ^I3~ZYj#wBrTld-yZH}XP`u>4r!*{_ua z17pi!b5?4x})!Q*xqT~~Gb%4-je2=*&pEJ0*njuY&{&J| zI89S4=pI5W%lxqrBK)CU-LGjcNaCBzQPXUvS-2jU0NQ?}YQDl)y%4fl;!Z`{q`XK53=0XY738^?dIRcmt768ZPn@=%S+qn~*X}Kzh$Z9pxEMVKaLzOm#HY+lCL$mH9XWUXL z(ZHlPy>Q1V9nDap72zFcROxr3QqMWWHqh}!Gc`3^v&z;bFmMoGvKkPuG zT{F9LTqo`mkr`jp(69a_mS_>gZ;yZYOkc;$%e*3Ux>= z2T+;@?Yb(Ln*HhU(0i!cFl;Qw zH=+iJXw~*dmko@~B*(}Vl|mI$_$v3HjaOaoY?$m@scf$v;6S1b58-x`H-4X7BZ(U@ zI|7y=VD1G=qqffvmQEHhGxO*tVF+8>KLivyr}tc8@(vV5M^@A{s^tBN9UMYvQ_Rp~36XENU@7C8-w> z`RTQxI`=(^q}ttfm6Mv8UsGiJ#q-s`zz>!2fCO2Z3Hb8( zZ>j>JtSxWmlY+tK$_3l>`-fITf;GAso1h=pZ;B@rfF_>xYL8PlagQR{{)@f#72uNe zLI*v@c(O0QmD7)308PBSMDok4@vl8roEad9sD~b3CuiG#Ow! zNB&r?zxAAw0*bipk0ZQq(KcO%N$vSp0!cywFnM1G1fqi?@C)1Q{8UZol;KCxEABe9 zxdeGVfeUN5;rKsN=!cM8-qZccqq*KLXK{ePCcRzc8VVh`LLGK45U>_x)OO z{O{yCS8_DABmQ=YMKWEG=6^4Eg!`yNfGBnu zHcSKhfxPx9bb6}0(L<0tfW#&;>|9Hv`=t(`tqX^+1A`*Z&1j7++y*9PyFV$Y1Y$rK z`6+`y?=cp|7hca8)fnAlb3Qyv@JQ0}A^BarBOaG!7?(wV&q3~Tz#fJyC#%=n|@;P@aVZMv=PEc zxnxnoP*Pwuu0+%;n}ts+3GR$IYowK*B@ki*a*q`$uBjU-lBzZ=_2OOWC$GzR<5lk_ zHe^T(Jwj(}B>5@3|74ExKSf7v>CZgZ03y0P=-FoT+aoJVi24qgVZXCqXEFVKGk{32 zmx&vj8=!BeC~YLH5vkVPl%cQW+r5a9nIojAlW(KkTHsl5w9;ir-wI4p)S}1s=rhFX zl0dp;_adMn@9krO6RFFK@YH)sXM62kM2~e25nJra@uL5Y#%Ou~*fnmPcv;1~nkf0$ z^2bHhzuwASSwu!4t$?{_+CeH#zl;9`q75&2+t9m;HIuT)1toIFIH(TaQg<_n>kbg7i^`o>&{IW(%m;TMDst*5EX6+XzUJkA z2lmed^)s^9LK9)}AJ$i#xmG{R_s|h7H>-u`zhP1VUT2*_<*2&ZP4@jZg%aO;I ziwn*P(;>T2T6mHFsVwoZIqOTEldIdF1=CL;y@MJRtD9#+|%bu z5?E462|APG9P(_FKOD-9F4-P1Z+Q^xO_i#=z0vwlv-SoU#9EdG)l(MW--s&?+w+#+QfyEo zC(!q;MEgBo-4MaX$|(Ip#5;@DOm;O;AIum4%5?dlUbe_GtBX?Qn`mf@gV}rLhXM=? z!bh#U@Q+&kOFTjsBtU!@T$f<{F@@$`aSZ;Vzu~y#z*gXO=sBp9zp-m(te2;0(k807 zWKWF7LL@5T1x?uDk^?Z#MtGa9N6oTDoR8NgR%u!r7Pjuk!&`E^nmRWRahr7X>1CXB zdR7Q_a4nGv2Qq#zxl3nZrb-W45wzH$|A5ezQX6HPil~pRU!)-(tk8n)&4&9_HL5HM z;jd%x$ggt2%(@K&88IX&gGk$Qd9V1ze0Toc2hfjeQJJidW;nJGbXO9f4r3VZ$3w2m zWY2ik`D&o&qqD_0o9C7{rd*RWBgi_-|BGN@8&##yCqAN#*yr|x{*LPut>u#YZG#M) z_&$hcf4afmP!iFYBSV2nvXD2$o+;Sb)u85_Y?Nm`&9_dSZbSo6uAxWoSwn9xa(sj|eDZ&49fd-N z|D@jfe{s(AzVLiWuL-cEpxmawvM4ukG8URX`&<0KrfJN7@vzcy@%i9AO?X7~@^6L#i6v0<) zL^W~UkyB?|5vqsX$`k@P>~No>SNro2>H>hhPha^JhZ)cSHl8LP!Lv{RG;ryxAU3xSPr z=WkLmwQ&mm+PBurl0!eci96)Pz;m*;u|Oy9946E2)kk?Y3Fga;CmP{-Y?^cY(Kx!} zd?Tk3?En|xcnb^-wj8s+eyx_L0i^Uk_O5GteXY1>y%&v=$qfOk`9_qO*wgMNQvZtQ z(0{66i*f$(2BaDkXMShK+~d%(@H?@Tw)v@C9#RJf6Z{W27=_K20=rW58jD>b4v-*pr0X~{=N3j? zNTNvjBmaAG(sK4k+2b#vT$_qNIsn@VqfK=vZbcfhk+l2BP!EN|_);I3tNFPMMJ;y> zBDc}&;8hNa`a%t(X)EUS2LX?@0mAVe$VpqAnMRh(lE&%Yj}X~8mZezmCfO@k=w8*U z`5h5Tsf*;H*#Snjz?cnUwkdMRhtVS>x-`!9h^#4ud}R-dK*8GxgilF7^gHt#HoR5Y z*k)RbZru~VAjq%Bw=sO>d1zoSb1W{rq(rc{KwnE05o*y;|4HdQqIA9hrv}Y42YeH=(_ton{nRerGA~kFfF^2 z%Q!^pR-tH$)EX_)V=7s6ik)f@c0q2`_{0(c9tvMvUi|&H36h2-e}G#^Ko z?GJG9AKY6Om{1FDOFJ1vM_U<^bKh4J5xN0vuap!iH*sC-8`GcPP0>Xd*&PNG!1vUR>M(&4a!6AO(Fj&*q*~$17pnl+kL6}~vK=XmtjgI4 zde|JfAl@F~WQ`*U=0BGyI~@E~lMN1@{R(BL>MFgdMx>DaylU1AANq-xyp&t{Z(vU$ zRi=iJah5K$76V34D?`O&&W%R;R4Pb|rEd2cZL@AGU!xbhyc+AtIf&9X@^-l0M`hrZ zw1nXuTYWqRvz`a5DL3;R<7Xx81Q{AD;=VmMC2usx?s2Fd1zNa#pT+-`%8JX2Bb>ckoU5>(aUWb)a5J+n{ueRxEYokkPO%joMF;=np zE%c7mlB0_VJ7hilqKz=itR6$L(@u?66ixV27h$k!ey_}5KERq?{Nze+%pI7h%O5x_ zNTLV7Ze@)WK@O;VgIJ)Q6;_(@ESEE<)j-!}zF%m7bRhVcZ))DzBkuv~h~tA6Ot4jf z%VoWYD?{FZ(FwqD#9w;I26a}PVM=N%BsToi=iGrj-jh8c;w z#E$->Qpp)f`dU3czq5sQ5>az%Fl#^1D7?g<(L6k-N+!XH{b0;28<^+H=tOWXL0%B? z?fKkUs4jz!DT0>o?blQ%OaFDPSf=UHri(4f8EAQ-CfbF4dbv8_diSs7UZg;wms`+N zbfV9}3H?c?;}v+c4*QnoB}}I2%Cl+BRy6#{(D0H7KVpf&H|}o>flT6~*XiB;^@ksY z$ES3fT1s?;QUR7`dfAZb%G+$I&&wP;WN|gjV1_ZCaf23ZwS~)>+oF}9LYHv#Ef$DW10dT4s+yVs+W2pdaxZ%CT2*^McD z*OfQ=;%fmWYE7rWsdHESPfd*v5VfNF(R;?yb2Z0#-3s_>CnvVU0|cFE3a%hks!d{1 zAA;^aIXZ5&|C!(71J48(Tj>5ba}&nxc*)XOOQGVp5g8jTAwRbchmb40J^<=RYIU%x!uwgKY4CM&J}urX$DNToNoJ z_zR=IpHT?PrgHy1uM&#TUrr^QbvYta3xDJ*2+5$APeWbeQ6UY?%D<88N^#~ZqkI_2 z22E1WhhIXr8H04OE@yYBs8RT>8TBpyu)ax%UMckar$HK7O1JbHP}WMPcH^#l^(nk8 zHv7|}?VrMm#yyjGR~G==6_rQwDq z2aYQ0y=r%$$Q$cH8DA6-!tp9af~+>M=0lM)ukwB;@;WH69#v&yu2nBiDUEZqo#9Hj z;O?|!jZ2GFhAEeS0jM@a(>0KXHZ!59X9Rit7bgnm8>( zkqmGpBW|`v$qJb>bsK`GNhwtGk-QYUKD0#lETj(PIxDQAhZ+@M<1aZZ0UcQ>hWh(r z0+vK)_8p;%u>XP^*R&aojD|m6nchGu)X1c_*lE_Y!K*Tfrv$b3h~y)p8d4&}N0tnZ z`6bF4K9tWTc)vR-C>1bRk%?xQ%{%tt7-$@k$_gVRjJbgc*<+gE4(uqb+)Asy4k!4k zsm)f|J|8NsZ>~J3aS4j{BL65xkH8qgFd71Sp9vCe&!y*QXdXnJ6e86{6S80bbUoh- zq_EUT)}ymca?O7|luRfD*9~qvGcHzYbTQgK1H#z{!w4KhaB11B)8MDiE7R<#bz z-ZdolN_~Biu=7o-Ocq8KXFjcYf%2i@Sb1cB68mHeV=b^a7&_-oX6%c}K&2F#0LAcw zm%A*;%bMfb=Nh9m@a@0l5DUY65lYKv(C(zXSzT=G$gX?moC)TV*dBH<(Yp6(JVKSkhf1)15c{no@W{uR3Yn=_}4Qy3WPzI+q& zHRsCA*~#D=M}4(MRsVqf8b8uxVi*Lg8#y2s({p;w=6nrJJ*aR#WVf+*m0+}!pNoB6 zSaZ#f&HMJKvvIucnuQAF$cMbCi$HvJ)5kH-KAi{ihY_t0+Qb}2%TId0D$wt@qpjJd zlVD6lt%+rJWH_=*@_Pl*B0hYmIH=t!Hd;mZ90K*D6BfsM&|=;BE>pGe(D?n7x2@4XC>Ihk&~ggfl|9G%sQU0X{cS@f6d!Eu}T zB>TFGaSJc&S2%vrbPS;0QUrp;&wS#Y6nLE)7*f)K;W28wZR2vrd%fZhvWuNn6%wrv zm6Fz)ldVrli;LBDT6H;WdQPQ9V(PCg>v^u+VP*0G)UH!*s%ZQ+PkiIbqbEnVmWzHR zkFV^u&&Nb{0_C=Rr}5X3{Itk74n-DD`Ii_(MP}qAi+*{1ts2;#yp1#urLBH8G0LBU ztnf%sVnF}6+t+4L{J{zO+RW~umlL+RDfvzc;htD^oNgP=WW2ca;8JiCR zG8XjVHWP2RK>>i9=?4AcM+?tAQvs4AN#Ul)RzewGT@Bgo@0$Vc`!{o!NTu{TWsu{_ zr^f)IDxhyyr^}^W%(5|^&DAHt;H8A&>&>E;={=18f@;Sy@@@L+Xt_9guW^nC>7v^H zJ=&bVObaiXXzGIaIm}C9K*G)L>*`6lV9FX;_*cW7YLq!LRXFgDfYt^W%!rqkZ+SP4 z&dG9jQwZ1^t(j5W*VXx}+)qMmTsutgWd{WqJLXcT_AHOQ z+R?*Cra31_eg9@v?uO!xIK>)lT`HOjI#BopE%r|H-;QE>y>eJJL}#7#2kE1$smO1YMCe#a9DHQnhPt+1%6wzKO`2CwmiZw0n5`=QW2#`Adsy{^3JsbX?X zU%(;4#9x$s|3)~C=!+t5qk`iYYInQyU1a`ScIHydc)P8bC-WFzUO0+Y`*GE%gvp>w zopnq{A8(&V!?H&MR-s-&N|P}h3bC)q6dvxpT9;6ahty?MNx=8^@>18?8Rd0lk8Sm&a)mIm9a1U?;f2OL%PIJX}niu5eBg(Nh#>FeaLbs5pZn=8?j6+(Lmg z$+R*)ByOp1hVA)19AbN$F}_^F-*YDaDeFh8x|880h-%(n?ae300fwj3jAT3&YccfO zhJib*fXX4q_raIWK9!@ZE$>?WJW`A~w;rF#&9&85q7ZQJ;iOUPa+K6F!uT{*1Wv^8 z>6!I)!^$4k^YilTgBl}-zp}WKw5EBDC}k%7*zCm=wXk|!%iTlc#{L= z(fQ5C?}DFnQfh_IvXkZn(*3Mqw&r72jELX-jpOc*+rA_frDk3gSC?Wz;L+cb{>2!9 z09L_m>SLRGW=%2E%bOC})Zn~@U!>4$Krf?c;B%W*_t@eQvQ@TwG4BUZlvK)lD4WBN ztAh=Hja-L<$FQ0zIpHzUUF}0IXU>m6!5B2&9iNbXdb3I;;O$qh$w?zE-Db^Zgu_ax zr(s`6231nNV^PoXTE%A{OB{Zh0@%dsVDU6$wCn!FSiclAwiD`2W{RWOZxiG^b^_d0 z#5z+OnAy^QzO+LHLj>g^`_{W1TWC;y4#6qTB=F94cd|Grtaz*T+rZX$zrksIFDML- z0{86_l0L7Q0pB;G@Kq?)pI?MrRI7C)Bj{gvZdU ^X~X-^KwgEl9x2B?am9ND4Lf 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�OhAfiVrxOIV+ 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 z -Date: Sun, 29 Nov 2015 14:44:22 +0200 -Subject: [PATCH] Revert "x86/mm/mtrr: Remove kernel internal MTRR interfaces: - unexport mtrr_add() and mtrr_del()" - -This reverts commit 2baa891e42d84159b693eadd44f6fe1486285bdc. - -It currently breaks nvidia304 driver. - -Signed-of-by: Thomas Backlund ---- - Documentation/x86/mtrr.txt | 20 ++++---------------- - arch/x86/kernel/cpu/mtrr/main.c | 2 ++ - 2 files changed, 6 insertions(+), 16 deletions(-) - -diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt -index dc3e703..860bc3a 100644 ---- a/Documentation/x86/mtrr.txt -+++ b/Documentation/x86/mtrr.txt -@@ -6,22 +6,10 @@ Luis R. Rodriguez - April 9, 2015 - =============================================================================== - Phasing out MTRR use - --MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by --drivers on Linux is now completely phased out, device drivers should use --arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on --non-PAT systems while a no-op but equally effective on PAT enabled systems. -- --Even if Linux does not use MTRRs directly, some x86 platform firmware may still --set up MTRRs early before booting the OS. They do this as some platform --firmware may still have implemented access to MTRRs which would be controlled --and handled by the platform firmware directly. An example of platform use of --MTRRs is through the use of SMI handlers, one case could be for fan control, --the platform code would need uncachable access to some of its fan control --registers. Such platform access does not need any Operating System MTRR code in --place other than mtrr_type_lookup() to ensure any OS specific mapping requests --are aligned with platform MTRR setup. If MTRRs are only set up by the platform --firmware code though and the OS does not make any specific MTRR mapping --requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID. -+MTRR use is replaced on modern x86 hardware with PAT. Over time the only type -+of effective MTRR that is expected to be supported will be for write-combining. -+As MTRR use is phased out device drivers should use arch_phys_wc_add() to make -+MTRR effective on non-PAT systems while a no-op on PAT enabled systems. - - For details refer to Documentation/x86/pat.txt. - -diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c -index f891b47..e7ed0d8 100644 ---- a/arch/x86/kernel/cpu/mtrr/main.c -+++ b/arch/x86/kernel/cpu/mtrr/main.c -@@ -448,6 +448,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, - return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, - increment); - } -+EXPORT_SYMBOL(mtrr_add); - - /** - * mtrr_del_page - delete a memory type region -@@ -536,6 +537,7 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) - return -EINVAL; - return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); - } -+EXPORT_SYMBOL(mtrr_del); - - /** - * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable --- -2.3.10 - diff --git a/kernel/kernel/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch b/kernel/kernel/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch new file mode 100644 index 00000000..939960bf --- /dev/null +++ b/kernel/kernel/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch @@ -0,0 +1,192 @@ +From 760235cd6ca8ae0d7509055d75a0f1d8b3c60668 Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Wed, 30 Nov 2016 15:21:12 +0800 +Subject: [PATCH] ACPICA: Events: Fix acpi_ev_initialize_region() return value + +ACPICA commit 543342ab7a676f4eb0c9f100d349388a84dff0e8 + +This patch changes acpi_ev_initialize_region(), stop returning AE_NOT_EXIST +from it so that, not only in acpi_ds_load2_end_op(), but all places invoking +this function won't emit exceptions. The exception can be seen in +acpi_ds_initialize_objects() when certain table loading mode is chosen. + +This patch also removes useless acpi_ns_locked from acpi_ev_initialize_region() +as this function will always be invoked with interpreter lock held now, and +the lock granularity has been tuned to lock around _REG execution, thus it +is now handled by acpi_ex_exit_interpreter(). Lv Zheng. + +Link: https://github.com/acpica/acpica/commit/543342ab +Signed-off-by: Lv Zheng +Signed-off-by: Bob Moore +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/acpica/acevents.h | 4 +-- + drivers/acpi/acpica/dsopcode.c | 2 +- + drivers/acpi/acpica/dswload2.c | 13 +--------- + drivers/acpi/acpica/evrgnini.c | 59 +++++++++++++++++------------------------- + 4 files changed, 27 insertions(+), 51 deletions(-) + +diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h +index 92fa47c..8a0049d 100644 +--- a/drivers/acpi/acpica/acevents.h ++++ b/drivers/acpi/acpica/acevents.h +@@ -243,9 +243,7 @@ acpi_ev_default_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +-acpi_status +-acpi_ev_initialize_region(union acpi_operand_object *region_obj, +- u8 acpi_ns_locked); ++acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj); + + /* + * evsci - SCI (System Control Interrupt) handling/dispatch +diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c +index 4cc9d98..77fd7c8 100644 +--- a/drivers/acpi/acpica/dsopcode.c ++++ b/drivers/acpi/acpica/dsopcode.c +@@ -84,7 +84,7 @@ acpi_status acpi_ds_initialize_region(acpi_handle obj_handle) + + /* Namespace is NOT locked */ + +- status = acpi_ev_initialize_region(obj_desc, FALSE); ++ status = acpi_ev_initialize_region(obj_desc); + return (status); + } + +diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c +index e362182..651f35a 100644 +--- a/drivers/acpi/acpica/dswload2.c ++++ b/drivers/acpi/acpica/dswload2.c +@@ -609,18 +609,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) + + status = + acpi_ev_initialize_region +- (acpi_ns_get_attached_object(node), FALSE); +- +- if (ACPI_FAILURE(status)) { +- /* +- * If AE_NOT_EXIST is returned, it is not fatal +- * because many regions get created before a handler +- * is installed for said region. +- */ +- if (AE_NOT_EXIST == status) { +- status = AE_OK; +- } +- } ++ (acpi_ns_get_attached_object(node)); + break; + + case AML_NAME_OP: +diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c +index 75ddd16..a909225 100644 +--- a/drivers/acpi/acpica/evrgnini.c ++++ b/drivers/acpi/acpica/evrgnini.c +@@ -479,7 +479,6 @@ acpi_ev_default_region_setup(acpi_handle handle, + * FUNCTION: acpi_ev_initialize_region + * + * PARAMETERS: region_obj - Region we are initializing +- * acpi_ns_locked - Is namespace locked? + * + * RETURN: Status + * +@@ -497,19 +496,28 @@ acpi_ev_default_region_setup(acpi_handle handle, + * MUTEX: Interpreter should be unlocked, because we may run the _REG + * method for this region. + * ++ * NOTE: Possible incompliance: ++ * There is a behavior conflict in automatic _REG execution: ++ * 1. When the interpreter is evaluating a method, we can only ++ * automatically run _REG for the following case: ++ * operation_region (OPR1, 0x80, 0x1000010, 0x4) ++ * 2. When the interpreter is loading a table, we can also ++ * automatically run _REG for the following case: ++ * operation_region (OPR1, 0x80, 0x1000010, 0x4) ++ * Though this may not be compliant to the de-facto standard, the ++ * logic is kept in order not to trigger regressions. And keeping ++ * this logic should be taken care by the caller of this function. ++ * + ******************************************************************************/ + +-acpi_status +-acpi_ev_initialize_region(union acpi_operand_object *region_obj, +- u8 acpi_ns_locked) ++acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj) + { + union acpi_operand_object *handler_obj; + union acpi_operand_object *obj_desc; + acpi_adr_space_type space_id; + struct acpi_namespace_node *node; +- acpi_status status; + +- ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); ++ ACPI_FUNCTION_TRACE(ev_initialize_region); + + if (!region_obj) { + return_ACPI_STATUS(AE_BAD_PARAMETER); +@@ -580,39 +588,17 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, + handler_obj, region_obj, + obj_desc)); + +- status = +- acpi_ev_attach_region(handler_obj, +- region_obj, +- acpi_ns_locked); ++ (void)acpi_ev_attach_region(handler_obj, ++ region_obj, FALSE); + + /* + * Tell all users that this region is usable by + * running the _REG method + */ +- if (acpi_ns_locked) { +- status = +- acpi_ut_release_mutex +- (ACPI_MTX_NAMESPACE); +- if (ACPI_FAILURE(status)) { +- return_ACPI_STATUS(status); +- } +- } +- + acpi_ex_exit_interpreter(); +- status = +- acpi_ev_execute_reg_method(region_obj, +- ACPI_REG_CONNECT); ++ (void)acpi_ev_execute_reg_method(region_obj, ++ ACPI_REG_CONNECT); + acpi_ex_enter_interpreter(); +- +- if (acpi_ns_locked) { +- status = +- acpi_ut_acquire_mutex +- (ACPI_MTX_NAMESPACE); +- if (ACPI_FAILURE(status)) { +- return_ACPI_STATUS(status); +- } +- } +- + return_ACPI_STATUS(AE_OK); + } + } +@@ -622,12 +608,15 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, + node = node->parent; + } + +- /* If we get here, there is no handler for this region */ +- ++ /* ++ * If we get here, there is no handler for this region. This is not ++ * fatal because many regions get created before a handler is installed ++ * for said region. ++ */ + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "No handler for RegionType %s(%X) (RegionObj %p)\n", + acpi_ut_get_region_name(space_id), space_id, + region_obj)); + +- return_ACPI_STATUS(AE_NOT_EXIST); ++ return_ACPI_STATUS(AE_OK); + } +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch b/kernel/kernel/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch new file mode 100644 index 00000000..a248ba34 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch @@ -0,0 +1,34 @@ +From 124298bd03acebd9c9da29a794718aca31bec1f7 Mon Sep 17 00:00:00 2001 +From: Daniel Roschka +Date: Wed, 22 Feb 2017 15:17:29 -0700 +Subject: [PATCH] nvme: detect NVMe controller in recent MacBooks + +Adds support for detection of the NVMe controller found in the +following recent MacBooks: +- Retina MacBook 2016 (MacBook9,1) +- 13" MacBook Pro 2016 without Touch Bar (MacBook13,1) +- 13" MacBook Pro 2016 with Touch Bar (MacBook13,2) + +Signed-off-by: Daniel Roschka +Reviewed-by: Christoph Hellwig +Signed-off-by: Sagi Grimberg +Signed-off-by: Jens Axboe +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index d38dae9..319f5c5 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2120,6 +2120,7 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, + { 0, } + }; + MODULE_DEVICE_TABLE(pci, nvme_id_table); +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch b/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch new file mode 100644 index 00000000..3a010204 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch @@ -0,0 +1,38 @@ +From fc8e9c54699e42754094ff475da46440778d8f19 Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Thu, 4 Aug 2016 12:54:22 +0800 +Subject: [PATCH] drm/amd/amdgpu: add Polaris12 PCI ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 8cb937b..2534ada 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -418,6 +418,13 @@ static const struct pci_device_id pciidlist[] = { + {0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, ++ /* Polaris12 */ ++ {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + + {0, 0, 0} + }; +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch b/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch new file mode 100644 index 00000000..7b8a1133 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch @@ -0,0 +1,469 @@ +From c4642a479fac9f5c224ff7425d86c427b94011af Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Wed, 14 Dec 2016 15:32:28 -0500 +Subject: [PATCH] drm/amd/amdgpu: add Polaris12 support (v3) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +v2: agd: squash in various fixes +v3: agd: squash in: +drm/amdgpu: remove unnecessary smc sk firmware for polaris12 + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +[ rebased for 4.9 / tmb ] +Signed-off-by: Thomas Backlund +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 3 +++ + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++ + drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 13 ++++++++++--- + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 31 +++++++++++++++++++++++++----- + drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 6 ++++++ + drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 5 +++-- + drivers/gpu/drm/amd/amdgpu/vi.c | 10 ++++++++++ + drivers/gpu/drm/amd/include/amd_shared.h | 1 + + 11 files changed, 76 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +index 9ada56c..4c851fde 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +@@ -840,6 +840,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, + else if (type == CGS_UCODE_ID_SMU_SK) + strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin"); + break; ++ case CHIP_POLARIS12: ++ strcpy(fw_name, "amdgpu/polaris12_smc.bin"); ++ break; + default: + DRM_ERROR("SMC firmware not supported\n"); + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 60bd4af..fe3bb94 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -73,6 +73,7 @@ static const char *amdgpu_asic_name[] = { + "STONEY", + "POLARIS10", + "POLARIS11", ++ "POLARIS12", + "LAST", + }; + +@@ -1277,6 +1278,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev) + case CHIP_FIJI: + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_CARRIZO: + case CHIP_STONEY: + if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index a81dfae..1d564be 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -65,6 +65,7 @@ + #define FIRMWARE_STONEY "amdgpu/stoney_uvd.bin" + #define FIRMWARE_POLARIS10 "amdgpu/polaris10_uvd.bin" + #define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin" ++#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin" + + /** + * amdgpu_uvd_cs_ctx - Command submission parser context +@@ -98,6 +99,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); + MODULE_FIRMWARE(FIRMWARE_STONEY); + MODULE_FIRMWARE(FIRMWARE_POLARIS10); + MODULE_FIRMWARE(FIRMWARE_POLARIS11); ++MODULE_FIRMWARE(FIRMWARE_POLARIS12); + + static void amdgpu_uvd_idle_work_handler(struct work_struct *work); + +@@ -149,6 +151,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) + case CHIP_POLARIS11: + fw_name = FIRMWARE_POLARIS11; + break; ++ case CHIP_POLARIS12: ++ fw_name = FIRMWARE_POLARIS12; ++ break; + default: + return -EINVAL; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +index 69b66b9..8fec802 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +@@ -52,6 +52,7 @@ + #define FIRMWARE_STONEY "amdgpu/stoney_vce.bin" + #define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin" + #define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin" ++#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin" + + #ifdef CONFIG_DRM_AMDGPU_CIK + MODULE_FIRMWARE(FIRMWARE_BONAIRE); +@@ -66,6 +67,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); + MODULE_FIRMWARE(FIRMWARE_STONEY); + MODULE_FIRMWARE(FIRMWARE_POLARIS10); + MODULE_FIRMWARE(FIRMWARE_POLARIS11); ++MODULE_FIRMWARE(FIRMWARE_POLARIS12); + + static void amdgpu_vce_idle_work_handler(struct work_struct *work); + +@@ -121,6 +123,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) + case CHIP_POLARIS11: + fw_name = FIRMWARE_POLARIS11; + break; ++ case CHIP_POLARIS12: ++ fw_name = FIRMWARE_POLARIS12; ++ break; + + default: + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +index b3d62b9..2006abb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +@@ -167,6 +167,7 @@ static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(stoney_golden_settings_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + polaris11_golden_settings_a11, + (const u32)ARRAY_SIZE(polaris11_golden_settings_a11)); +@@ -608,6 +609,7 @@ static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev) + num_crtc = 6; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + num_crtc = 5; + break; + default: +@@ -1589,6 +1591,7 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev) + adev->mode_info.audio.num_pins = 8; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + adev->mode_info.audio.num_pins = 6; + break; + default: +@@ -2388,7 +2391,8 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc) + int pll; + + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + struct amdgpu_encoder *amdgpu_encoder = + to_amdgpu_encoder(amdgpu_crtc->encoder); + struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; +@@ -2822,7 +2826,8 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc, + return -EINVAL; + + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + struct amdgpu_encoder *amdgpu_encoder = + to_amdgpu_encoder(amdgpu_crtc->encoder); + int encoder_mode = +@@ -2992,6 +2997,7 @@ static int dce_v11_0_early_init(void *handle) + adev->mode_info.num_dig = 6; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + adev->mode_info.num_hpd = 5; + adev->mode_info.num_dig = 5; + break; +@@ -3101,7 +3107,8 @@ static int dce_v11_0_hw_init(void *handle) + amdgpu_atombios_crtc_powergate_init(adev); + amdgpu_atombios_encoder_init_dig(adev); + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk, + DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS); + amdgpu_atombios_crtc_set_dce_clock(adev, 0, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index d0ec009..3733741 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -138,6 +138,13 @@ MODULE_FIRMWARE("amdgpu/polaris10_mec.bi + MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin"); + ++MODULE_FIRMWARE("amdgpu/polaris12_ce.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_me.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mec.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin"); ++ + static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] = + { + {mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0}, +@@ -687,6 +694,7 @@ static void gfx_v8_0_init_golden_registe + (const u32)ARRAY_SIZE(tonga_golden_common_all)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -901,6 +909,9 @@ static int gfx_v8_0_init_microcode(struc + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_STONEY: + chip_name = "stoney"; + break; +@@ -1777,6 +1788,7 @@ static int gfx_v8_0_gpu_early_init(struc + gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + ret = amdgpu_atombios_get_gfx_info(adev); + if (ret) + return ret; +@@ -2695,6 +2707,7 @@ static void gfx_v8_0_tiling_mode_table_i + + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | +@@ -3516,6 +3529,7 @@ gfx_v8_0_raster_config(struct amdgpu_dev + *rconf1 |= 0x0; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) | + SE_XSEL(1) | SE_YSEL(1); + *rconf1 |= 0x0; +@@ -4029,7 +4043,8 @@ static void gfx_v8_0_init_pg(struct amdg + cz_enable_cp_power_gating(adev, true); + else + cz_enable_cp_power_gating(adev, false); +- } else if (adev->asic_type == CHIP_POLARIS11) { ++ } else if ((adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS11)) { + gfx_v8_0_init_power_gating(adev); + } + } +@@ -4100,7 +4115,8 @@ static int gfx_v8_0_rlc_resume(struct am + RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK); + WREG32(mmRLC_CGCG_CGLS_CTRL, tmp); + if (adev->asic_type == CHIP_POLARIS11 || +- adev->asic_type == CHIP_POLARIS10) { ++ adev->asic_type == CHIP_POLARIS10 || ++ adev->asic_type == CHIP_POLARIS12) { + tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D); + tmp &= ~0x3; + WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp); +@@ -4288,6 +4304,7 @@ static int gfx_v8_0_cp_gfx_start(struct + amdgpu_ring_write(ring, 0x0000002A); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_ring_write(ring, 0x16000012); + amdgpu_ring_write(ring, 0x00000000); + break; +@@ -4938,7 +4955,8 @@ static int gfx_v8_0_cp_compute_resume(st + (adev->asic_type == CHIP_FIJI) || + (adev->asic_type == CHIP_STONEY) || + (adev->asic_type == CHIP_POLARIS11) || +- (adev->asic_type == CHIP_POLARIS10)) { ++ (adev->asic_type == CHIP_POLARIS10) || ++ (adev->asic_type == CHIP_POLARIS12)) { + WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, + AMDGPU_DOORBELL_KIQ << 2); + WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, +@@ -4974,7 +4992,8 @@ static int gfx_v8_0_cp_compute_resume(st + mqd->cp_hqd_persistent_state = tmp; + if (adev->asic_type == CHIP_STONEY || + adev->asic_type == CHIP_POLARIS11 || +- adev->asic_type == CHIP_POLARIS10) { ++ adev->asic_type == CHIP_POLARIS10 || ++ adev->asic_type == CHIP_POLARIS12) { + tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL); + tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1); + WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp); +@@ -5488,7 +5507,8 @@ static int gfx_v8_0_late_init(void *hand + static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, + bool enable) + { +- if (adev->asic_type == CHIP_POLARIS11) ++ if ((adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) + /* Send msg to SMU via Powerplay */ + amdgpu_set_powergating_state(adev, + AMD_IP_BLOCK_TYPE_SMC, +@@ -5565,6 +5585,7 @@ static int gfx_v8_0_set_powergating_stat + gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable) + gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true); + else +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +index 0daac3a..476bc9f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +@@ -46,6 +46,7 @@ static int gmc_v8_0_wait_for_idle(void *handle); + MODULE_FIRMWARE("amdgpu/tonga_mc.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_mc.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_mc.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mc.bin"); + + static const u32 golden_settings_tonga_a11[] = + { +@@ -130,6 +131,7 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -225,6 +227,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_FIJI: + case CHIP_CARRIZO: + case CHIP_STONEY: +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +index 1170a64..034ace7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +@@ -60,6 +60,8 @@ MODULE_FIRMWARE("amdgpu/polaris10_sdma.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin"); + + + static const u32 sdma_offsets[SDMA_MAX_INSTANCE] = +@@ -206,6 +208,7 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -278,6 +281,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_CARRIZO: + chip_name = "carrizo"; + break; +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +index 6b3293a..5fb0b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +@@ -320,11 +320,12 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) + { + u32 tmp; + +- /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ ++ /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */ + if ((adev->asic_type == CHIP_FIJI) || + (adev->asic_type == CHIP_STONEY) || + (adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) + return AMDGPU_VCE_HARVEST_VCE1; + + /* Tonga and CZ are dual or single pipe */ +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index bf088d6..c2ac54f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -88,6 +88,7 @@ MODULE_FIRMWARE("amdgpu/polaris10_smc.bi + MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_smc.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_smc.bin"); + + /* + * Indirect registers accessor +@@ -312,6 +313,7 @@ static void vi_init_golden_registers(str + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + default: + break; + } +@@ -592,6 +594,7 @@ static int vi_read_register(struct amdgp + case CHIP_TONGA: + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_CARRIZO: + case CHIP_STONEY: + asic_register_table = cz_allowed_read_registers; +@@ -1465,6 +1468,7 @@ int vi_set_ip_blocks(struct amdgpu_devic + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + adev->ip_blocks = polaris11_ip_blocks_vd; + adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks_vd); + break; +@@ -1608,6 +1612,11 @@ static int vi_common_early_init(void *ha + adev->pg_flags = 0; + adev->external_rev_id = adev->rev_id + 0x50; + break; ++ case CHIP_POLARIS12: ++ adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG; ++ adev->pg_flags = 0; ++ adev->external_rev_id = adev->rev_id + 0x64; ++ break; + case CHIP_CARRIZO: + adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG | + AMD_CG_SUPPORT_GFX_MGCG | +@@ -1897,6 +1906,7 @@ static int vi_common_set_clockgating_sta + case CHIP_TONGA: + case CHIP_POLARIS10: + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + vi_common_set_clockgating_state_by_smu(adev, state); + default: + break; +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index c02469a..5f59117 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -46,6 +46,7 @@ enum amd_asic_type { + CHIP_STONEY, + CHIP_POLARIS10, + CHIP_POLARIS11, ++ CHIP_POLARIS12, + CHIP_LAST, + }; + +-- +2.10.2 diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch b/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch new file mode 100644 index 00000000..de592904 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch @@ -0,0 +1,32 @@ +From c10c8f7c27103bd7ac02d041d9d6e97296d48fc1 Mon Sep 17 00:00:00 2001 +From: Alex Deucher +Date: Fri, 10 Feb 2017 18:09:32 -0500 +Subject: [PATCH] drm/amdgpu/pm: check for headless before calling + compute_clocks + +Don't update display bandwidth on headless asics. + +bug: +https://bugs.freedesktop.org/show_bug.cgi?id=99387 + +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +index 95e026a..346e80a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +@@ -1283,7 +1283,9 @@ void amdgpu_pm_compute_clocks(struct amd + if (adev->pp_enabled) { + int i = 0; + +- amdgpu_display_bandwidth_update(adev); ++ if (adev->mode_info.num_crtc) ++ amdgpu_display_bandwidth_update(adev); ++ + for (i = 0; i < AMDGPU_MAX_RINGS; i++) { + struct amdgpu_ring *ring = adev->rings[i]; + if (ring && ring->ready) diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch b/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch new file mode 100644 index 00000000..7b2b0f63 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch @@ -0,0 +1,81 @@ +From f4309526576db325264b6dc9ee150ee70b330a42 Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Wed, 14 Dec 2016 15:40:48 -0500 +Subject: [PATCH] drm/amdgpu/powerplay: add Polaris12 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | 1 + + drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 3 ++- + drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c | 2 +- + drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | 1 + + 4 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +index fc592c2..95a568d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +@@ -98,6 +98,7 @@ static int amdgpu_pp_early_init(void *handle) + switch (adev->asic_type) { + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_TOPAZ: +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +index dc6700a..b036064 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +@@ -95,6 +95,7 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + polaris_set_asic_special_caps(hwmgr); + hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK); + break; +@@ -745,7 +746,7 @@ int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_TablelessHardwareInterface); + +- if (hwmgr->chip_id == CHIP_POLARIS11) ++ if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_SPLLShutdownSupport); + return 0; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +index 26477f0..6cd1287 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +@@ -521,7 +521,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr) + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); + result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10); + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); +- } else if (hwmgr->chip_id == CHIP_POLARIS11) { ++ } else if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) { + result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11); + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); + result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11); +diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +index e5812aa..6e618aa 100644 +--- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c ++++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +@@ -65,6 +65,7 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle) + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + polaris10_smum_init(smumgr); + break; + default: +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch b/kernel/kernel/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch deleted file mode 100644 index 7a90bae2..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 8726f2faa371514fba2f594d799db95203dfeee0 Mon Sep 17 00:00:00 2001 -From: Francisco Jerez -Date: Thu, 12 Jan 2017 12:44:54 +0200 -Subject: drm/i915: Remove WaDisableLSQCROPERFforOCL KBL workaround. - -The WaDisableLSQCROPERFforOCL workaround has the side effect of -disabling an L3SQ optimization that has huge performance implications -and is unlikely to be necessary for the correct functioning of usual -graphic workloads. Userspace is free to re-enable the workaround on -demand, and is generally in a better position to determine whether the -workaround is necessary than the DRM is (e.g. only during the -execution of compute kernels that rely on both L3 fences and HDC R/W -requests). - -The same workaround seems to apply to BDW (at least to production -stepping G1) and SKL as well (the internal workaround database claims -that it does for all steppings, while the BSpec workaround table only -mentions pre-production steppings), but the DRM doesn't do anything -beyond whitelisting the L3SQCREG4 register so userspace can enable it -when it sees fit. Do the same on KBL platforms. - -Improves performance of the GFXBench4 gl_manhattan31 benchmark by 60%, -and gl_4 (AKA car chase) by 14% on a KBL GT2 running Mesa master -- -This is followed by a regression of 35% and 10% respectively for the -same benchmarks and platform caused by my recent patch series -switching userspace to use the dataport constant cache instead of the -sampler to implement uniform pull constant loads, which caused us to -hit more heavily the L3 cache (and on platforms other than KBL had the -opposite effect of improving performance of the same two benchmarks). -The overall effect on KBL of this change combined with the recent -userspace change is respectively 4.6% and 2.6%. SynMark2 OglShMapPcf -was affected by the constant cache changes (though it improved as it -did on other platforms rather than regressing), but is not -significantly affected by this patch (with statistical significance of -5% and sample size 20). - -v2: Drop some more code to avoid unused variable warning. - -Fixes: 738fa1b3123f ("drm/i915/kbl: Add WaDisableLSQCROPERFforOCL") -Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99256 -Signed-off-by: Francisco Jerez -Cc: Matthew Auld -Cc: Eero Tamminen -Cc: Jani Nikula -Cc: Mika Kuoppala -Cc: beignet@lists.freedesktop.org -Cc: # v4.7+ -Reviewed-by: Mika Kuoppala -[Removed double Fixes tag] -Signed-off-by: Mika Kuoppala -Link: http://patchwork.freedesktop.org/patch/msgid/1484217894-20505-1-git-send-email-mika.kuoppala@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index db714dc..8acab87 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -970,18 +970,8 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, - uint32_t *batch, - uint32_t index) - { -- struct drm_i915_private *dev_priv = engine->i915; - uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - -- /* -- * WaDisableLSQCROPERFforOCL:kbl -- * This WA is implemented in skl_init_clock_gating() but since -- * this batch updates GEN8_L3SQCREG4 with default value we need to -- * set this bit here to retain the WA during flush. -- */ -- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -- l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; -- - wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index ab83fc2..49fa800 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1095,14 +1095,6 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE); - -- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes -- * involving this register should also be added to WA batch as required. -- */ -- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -- /* WaDisableLSQCROPERFforOCL:kbl */ -- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- GEN8_LQSC_RO_PERF_DIS); -- - /* WaToEnableHwFixForPushConstHWBug:kbl */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, --- -cgit v0.10.2 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch b/kernel/kernel/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch new file mode 100644 index 00000000..aaf9bb26 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch @@ -0,0 +1,42 @@ +From 853277481178fdf14d1a4e9e6ac7174d6046176f Mon Sep 17 00:00:00 2001 +From: Jani Nikula +Date: Wed, 1 Feb 2017 15:46:09 +0200 +Subject: [PATCH] drm/i915: don't warn about Skylake CPU - KabyPoint PCH combo + +Apparently there are machines out there with Skylake CPU and KabyPoint +PCH. Judging from our driver code, there doesn't seem to be any code +paths that would do anything different between SunrisePoint and +KabyPoint PCHs, so it would seem okay to accept the combo without +warnings. + +Fixes: 22dea0be50b2 ("drm/i915: Introduce Kabypoint PCH for Kabylake H/DT.") +References: https://lists.freedesktop.org/archives/intel-gfx/2017-February/118611.html +Reported-by: Rainer Koenig +Cc: Rainer Koenig +Cc: Rodrigo Vivi +Cc: # v4.8+ +Reviewed-by: Rodrigo Vivi +Signed-off-by: Jani Nikula +Link: http://patchwork.freedesktop.org/patch/msgid/1485956769-26015-1-git-send-email-jani.nikula@intel.com +(cherry picked from commit 3aac4acb89710fe782c9e78e7b1febf76e112c6c) +Signed-off-by: Jani Nikula +[ rebased for 4.9 / tmb ] +Signed-off-by: Thomas Backlund +--- + drivers/gpu/drm/i915/i915_drv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c +index b2c4a0b..8d63098 100644 +--- a/drivers/gpu/drm/i915/i915_drv.c ++++ b/drivers/gpu/drm/i915/i915_drv.c +@@ -207,7 +207,8 @@ static void intel_detect_pch(struct drm_ + } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_KBP; + DRM_DEBUG_KMS("Found KabyPoint PCH\n"); +- WARN_ON(!IS_KABYLAKE(dev)); ++ WARN_ON(!IS_SKYLAKE(dev) && ++ !IS_KABYLAKE(dev)); + } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || + (id == INTEL_PCH_P3X_DEVICE_ID_TYPE) || + ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch b/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch deleted file mode 100644 index 8cdf7198..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch +++ /dev/null @@ -1,127 +0,0 @@ -From a117f378f44150e6d13d2f19740fb757425b651f Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:44 +0300 -Subject: drm/i915/skl: drop workarounds for A0 and B0 revisions - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/7929af62a68504c84038a8db1625bd96ebaa9e6f.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 0568fb5..57da2b7 100644 ---- a/drivers/gpu/drm/i915/intel_dp.c -+++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -1299,10 +1299,6 @@ bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp) - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - -- /* WaDisableHBR2:skl */ -- if (IS_SKL_REVID(dev, 0, SKL_REVID_B0)) -- return false; -- - if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || - (INTEL_INFO(dev)->gen >= 9)) - return true; -diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c -index c438b02..0048b52 100644 ---- a/drivers/gpu/drm/i915/intel_dp_link_training.c -+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c -@@ -225,9 +225,6 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) - * Intel platforms that support HBR2 also support TPS3. TPS3 support is - * also mandatory for downstream devices that support HBR2. However, not - * all sinks follow the spec. -- * -- * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is -- * supported in source but still not enabled. - */ - source_tps3 = intel_dp_source_supports_hbr2(intel_dp); - sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd); -diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c -index 6fd39ef..acc1dbd 100644 ---- a/drivers/gpu/drm/i915/intel_guc_loader.c -+++ b/drivers/gpu/drm/i915/intel_guc_loader.c -@@ -375,9 +375,8 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv) - /* Enable MIA caching. GuC clock gating is disabled. */ - I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); - -- /* WaDisableMinuteIaClockGating:skl,bxt */ -- if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { -+ /* WaDisableMinuteIaClockGating:bxt */ -+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { - I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) & - ~GUC_ENABLE_MIA_CLOCK_GATING)); - } -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index 39417b7..47f7afa 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -269,8 +269,7 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine) - struct drm_i915_private *dev_priv = engine->i915; - - engine->disable_lite_restore_wa = -- (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) && -+ IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1) && - (engine->id == VCS || engine->id == VCS2); - - engine->ctx_desc_template = GEN8_CTX_VALID; -@@ -1068,9 +1067,8 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *engine, - { - uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - -- /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ -- if (IS_SKL_REVID(engine->i915, 0, SKL_REVID_B0) || -- IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) { -+ /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:bxt */ -+ if (IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) { - wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); - wa_ctx_emit(batch, index, -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 7a74750..2faf64f 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -851,15 +851,13 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, - GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); - -- /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) -+ /* WaDisableDgMirrorFixInHalfSliceChicken5:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) - WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, - GEN9_DG_MIRROR_FIX_ENABLE); - -- /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { -+ /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { - WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, - GEN9_RHWO_OPTIMIZATION_DISABLE); - /* -@@ -1023,15 +1021,8 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - GEN8_LQSC_RO_PERF_DIS); - - /* WaEnableGapsTsvCreditFix:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, REVID_FOREVER)) { -- I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | -- GEN9_GAPS_TSV_CREDIT_DISABLE)); -- } -- -- /* WaDisablePowerCompilerClockGating:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_B0, SKL_REVID_B0)) -- WA_SET_BIT_MASKED(HIZ_CHICKEN, -- BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); -+ I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | -+ GEN9_GAPS_TSV_CREDIT_DISABLE)); - - /* WaBarrierPerformanceFixDisable:skl */ - if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0)) --- -cgit v0.10.2 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch b/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch deleted file mode 100644 index 0643ccd9..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 9fc736e833d226853fd53843e35d6a1d542394ed Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:46 +0300 -Subject: drm/i915/skl: drop workarounds for D0 revision - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/d28d21ceddeec226b5d1a20a7382bee9a72709a4.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index 47f7afa..ca649cc 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -994,9 +994,8 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine, - struct drm_i915_private *dev_priv = engine->i915; - uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - -- /* WaDisableCtxRestoreArbitration:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_D0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) -+ /* WaDisableCtxRestoreArbitration:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) - wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); - - /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ -@@ -1095,9 +1094,8 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *engine, - wa_ctx_emit(batch, index, MI_NOOP); - } - -- /* WaDisableCtxRestoreArbitration:skl,bxt */ -- if (IS_SKL_REVID(engine->i915, 0, SKL_REVID_D0) || -- IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) -+ /* WaDisableCtxRestoreArbitration:bxt */ -+ if (IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) - wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); - - wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); -diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c -index 2df06b7..a860c40 100644 ---- a/drivers/gpu/drm/i915/intel_pm.c -+++ b/drivers/gpu/drm/i915/intel_pm.c -@@ -5335,8 +5335,7 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv) - rc6_mask = GEN6_RC_CTL_RC6_ENABLE; - DRM_INFO("RC6 %s\n", onoff(rc6_mask & GEN6_RC_CTL_RC6_ENABLE)); - /* WaRsUseTimeoutMode */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_D0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { - I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */ - I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | - GEN7_RC_CTL_TO_MODE | -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 474ce84..6880082 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1000,10 +1000,8 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - * until D0 which is the default case so this is equivalent to - * !WaDisablePerCtxtPreemptionGranularityControl:skl - */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_E0, REVID_FOREVER)) { -- I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, -- _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); -- } -+ I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, -+ _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - - if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) { - /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ -@@ -1023,12 +1021,6 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); - -- /* WaBarrierPerformanceFixDisable:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0)) -- WA_SET_BIT_MASKED(HDC_CHICKEN0, -- HDC_FENCE_DEST_SLM_DISABLE | -- HDC_BARRIER_PERFORMANCE_DISABLE); -- - /* WaDisableSbeCacheDispatchPortSharing:skl */ - if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0)) - WA_SET_BIT_MASKED( --- -cgit v0.10.2 - diff --git a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch b/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch deleted file mode 100644 index 1c8f8a38..00000000 --- a/kernel/kernel/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3be192e92ddcad15f7bf6b4b9e3f195eb8c1fe76 Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:47 +0300 -Subject: drm/i915/skl: drop workarounds for E0 revision - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/0633a02177195703502ef2396aab03efc0314334.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index ca649cc..2d8eb2e 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -845,13 +845,12 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, - uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - - /* -- * WaDisableLSQCROPERFforOCL:skl,kbl -+ * WaDisableLSQCROPERFforOCL:kbl - * This WA is implemented in skl_init_clock_gating() but since - * this batch updates GEN8_L3SQCREG4 with default value we need to - * set this bit here to retain the WA during flush. - */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0) || -- IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -+ if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) - l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; - - wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 6880082..68dc27f 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1003,20 +1003,6 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) { -- /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ -- I915_WRITE(FF_SLICE_CS_CHICKEN2, -- _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE)); -- } -- -- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes -- * involving this register should also be added to WA batch as required. -- */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) -- /* WaDisableLSQCROPERFforOCL:skl */ -- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- GEN8_LQSC_RO_PERF_DIS); -- - /* WaEnableGapsTsvCreditFix:skl */ - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); --- -cgit v0.10.2 - diff --git a/kernel/kernel/files/patches/mageia/net-wireguard.patch b/kernel/kernel/files/patches/mageia/net-wireguard.patch new file mode 100644 index 00000000..32c29f79 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/net-wireguard.patch @@ -0,0 +1,11839 @@ +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/config.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,321 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "config.h" ++#include "device.h" ++#include "socket.h" ++#include "packets.h" ++#include "timers.h" ++#include "hashtables.h" ++#include "peer.h" ++#include "uapi.h" ++ ++static int clear_peer_endpoint_src(struct wireguard_peer *peer, void *data) ++{ ++ socket_clear_peer_endpoint_src(peer); ++ return 0; ++} ++ ++static int set_device_port(struct wireguard_device *wg, u16 port) ++{ ++ socket_uninit(wg); ++ wg->incoming_port = port; ++ if (!(netdev_pub(wg)->flags & IFF_UP)) ++ return 0; ++ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL); ++ return socket_init(wg); ++} ++ ++static int set_ipmask(struct wireguard_peer *peer, void __user *user_ipmask) ++{ ++ int ret = -EINVAL; ++ struct wgipmask in_ipmask; ++ ++ if (copy_from_user(&in_ipmask, user_ipmask, sizeof(in_ipmask))) ++ return -EFAULT; ++ ++ if (in_ipmask.family == AF_INET && in_ipmask.cidr <= 32) ++ ret = routing_table_insert_v4(&peer->device->peer_routing_table, &in_ipmask.ip4, in_ipmask.cidr, peer); ++ else if (in_ipmask.family == AF_INET6 && in_ipmask.cidr <= 128) ++ ret = routing_table_insert_v6(&peer->device->peer_routing_table, &in_ipmask.ip6, in_ipmask.cidr, peer); ++ ++ return ret; ++} ++ ++static const u8 zeros[WG_KEY_LEN] = { 0 }; ++ ++static int set_peer(struct wireguard_device *wg, void __user *user_peer, size_t *len) ++{ ++ int ret = 0; ++ size_t i; ++ struct wgpeer in_peer; ++ void __user *user_ipmask; ++ struct wireguard_peer *peer = NULL; ++ ++ if (copy_from_user(&in_peer, user_peer, sizeof(in_peer))) ++ return -EFAULT; ++ ++ if (!memcmp(zeros, in_peer.public_key, NOISE_PUBLIC_KEY_LEN)) ++ return -EINVAL; /* Can't add a peer with no public key. */ ++ ++ peer = pubkey_hashtable_lookup(&wg->peer_hashtable, in_peer.public_key); ++ if (!peer) { /* Peer doesn't exist yet. Add a new one. */ ++ if (in_peer.flags & WGPEER_REMOVE_ME) ++ return -ENODEV; /* Tried to remove a non existing peer. */ ++ peer = peer_rcu_get(peer_create(wg, in_peer.public_key)); ++ if (!peer) ++ return -ENOMEM; ++ if (netdev_pub(wg)->flags & IFF_UP) ++ timers_init_peer(peer); ++ } ++ ++ if (in_peer.flags & WGPEER_REMOVE_ME) { ++ peer_put(peer); ++ peer_remove(peer); ++ goto out; ++ } ++ ++ if (in_peer.endpoint.addr.sa_family == AF_INET || in_peer.endpoint.addr.sa_family == AF_INET6) { ++ struct endpoint endpoint = { 0 }; ++ memcpy(&endpoint, &in_peer.endpoint, sizeof(in_peer.endpoint)); ++ socket_set_peer_endpoint(peer, &endpoint); ++ } ++ ++ if (in_peer.flags & WGPEER_REPLACE_IPMASKS) ++ routing_table_remove_by_peer(&wg->peer_routing_table, peer); ++ for (i = 0, user_ipmask = user_peer + sizeof(struct wgpeer); i < in_peer.num_ipmasks; ++i, user_ipmask += sizeof(struct wgipmask)) { ++ ret = set_ipmask(peer, user_ipmask); ++ if (ret) ++ break; ++ } ++ ++ if (in_peer.persistent_keepalive_interval != (u16)-1) { ++ const bool send_keepalive = !peer->persistent_keepalive_interval && in_peer.persistent_keepalive_interval && netdev_pub(wg)->flags & IFF_UP; ++ peer->persistent_keepalive_interval = (unsigned long)in_peer.persistent_keepalive_interval * HZ; ++ if (send_keepalive) ++ packet_send_keepalive(peer); ++ } ++ ++ if (netdev_pub(wg)->flags & IFF_UP) ++ packet_send_queue(peer); ++ ++ peer_put(peer); ++ ++out: ++ if (!ret) ++ *len = sizeof(struct wgpeer) + (in_peer.num_ipmasks * sizeof(struct wgipmask)); ++ ++ return ret; ++} ++ ++int config_set_device(struct wireguard_device *wg, void __user *user_device) ++{ ++ int ret = 0; ++ size_t i, offset; ++ struct wgdevice in_device; ++ void __user *user_peer; ++ bool modified_static_identity = false; ++ ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); ++ ++ mutex_lock(&wg->device_update_lock); ++ ++ if (copy_from_user(&in_device, user_device, sizeof(in_device))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (in_device.fwmark || (!in_device.fwmark && (in_device.flags & WGDEVICE_REMOVE_FWMARK))) { ++ wg->fwmark = in_device.fwmark; ++ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL); ++ } ++ ++ if (in_device.port) { ++ ret = set_device_port(wg, in_device.port); ++ if (ret) ++ goto out; ++ } ++ ++ if (in_device.flags & WGDEVICE_REPLACE_PEERS) ++ peer_remove_all(wg); ++ ++ if (in_device.flags & WGDEVICE_REMOVE_PRIVATE_KEY) { ++ noise_set_static_identity_private_key(&wg->static_identity, NULL); ++ modified_static_identity = true; ++ } else if (memcmp(zeros, in_device.private_key, WG_KEY_LEN)) { ++ noise_set_static_identity_private_key(&wg->static_identity, in_device.private_key); ++ modified_static_identity = true; ++ } ++ ++ if (in_device.flags & WGDEVICE_REMOVE_PRESHARED_KEY) { ++ noise_set_static_identity_preshared_key(&wg->static_identity, NULL); ++ modified_static_identity = true; ++ } else if (memcmp(zeros, in_device.preshared_key, WG_KEY_LEN)) { ++ noise_set_static_identity_preshared_key(&wg->static_identity, in_device.preshared_key); ++ modified_static_identity = true; ++ } ++ ++ if (modified_static_identity) ++ cookie_checker_precompute_keys(&wg->cookie_checker, NULL); ++ ++ for (i = 0, offset = 0, user_peer = user_device + sizeof(struct wgdevice); i < in_device.num_peers; ++i, user_peer += offset) { ++ ret = set_peer(wg, user_peer, &offset); ++ if (ret) ++ break; ++ } ++ ++out: ++ mutex_unlock(&wg->device_update_lock); ++ memzero_explicit(&in_device.private_key, NOISE_PUBLIC_KEY_LEN); ++ return ret; ++} ++ ++struct data_remaining { ++ void __user *data; ++ size_t out_len; ++ size_t count; ++}; ++ ++static inline int use_data(struct data_remaining *data, size_t size) ++{ ++ if (data->out_len < size) ++ return -EMSGSIZE; ++ data->out_len -= size; ++ data->data += size; ++ ++data->count; ++ return 0; ++} ++ ++static int calculate_ipmasks_size(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family) ++{ ++ size_t *count = ctx; ++ *count += sizeof(struct wgipmask); ++ return 0; ++} ++ ++static size_t calculate_peers_size(struct wireguard_device *wg) ++{ ++ size_t len = peer_total_count(wg) * sizeof(struct wgpeer); ++ routing_table_walk_ips(&wg->peer_routing_table, &len, calculate_ipmasks_size); ++ return len; ++} ++ ++static int populate_ipmask(void *ctx, union nf_inet_addr ip, u8 cidr, int family) ++{ ++ int ret; ++ struct data_remaining *data = ctx; ++ void __user *uipmask = data->data; ++ struct wgipmask out_ipmask; ++ ++ memset(&out_ipmask, 0, sizeof(struct wgipmask)); ++ ++ ret = use_data(data, sizeof(struct wgipmask)); ++ if (ret) ++ return ret; ++ ++ out_ipmask.cidr = cidr; ++ out_ipmask.family = family; ++ if (family == AF_INET) ++ out_ipmask.ip4 = ip.in; ++ else if (family == AF_INET6) ++ out_ipmask.ip6 = ip.in6; ++ ++ if (copy_to_user(uipmask, &out_ipmask, sizeof(out_ipmask))) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ ++static int populate_peer(struct wireguard_peer *peer, void *ctx) ++{ ++ int ret = 0; ++ struct data_remaining *data = ctx; ++ void __user *upeer = data->data; ++ struct wgpeer out_peer; ++ struct data_remaining ipmasks_data = { NULL }; ++ ++ memset(&out_peer, 0, sizeof(struct wgpeer)); ++ ++ ret = use_data(data, sizeof(struct wgpeer)); ++ if (ret) ++ return ret; ++ ++ memcpy(out_peer.public_key, peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN); ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ out_peer.endpoint.addr4 = peer->endpoint.addr4; ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ out_peer.endpoint.addr6 = peer->endpoint.addr6; ++ read_unlock_bh(&peer->endpoint_lock); ++ out_peer.last_handshake_time = peer->walltime_last_handshake; ++ out_peer.tx_bytes = peer->tx_bytes; ++ out_peer.rx_bytes = peer->rx_bytes; ++ out_peer.persistent_keepalive_interval = (u16)(peer->persistent_keepalive_interval / HZ); ++ ++ ipmasks_data.out_len = data->out_len; ++ ipmasks_data.data = data->data; ++ ret = routing_table_walk_ips_by_peer_sleepable(&peer->device->peer_routing_table, &ipmasks_data, peer, populate_ipmask); ++ if (ret) ++ return ret; ++ data->out_len = ipmasks_data.out_len; ++ data->data = ipmasks_data.data; ++ out_peer.num_ipmasks = ipmasks_data.count; ++ ++ if (copy_to_user(upeer, &out_peer, sizeof(out_peer))) ++ ret = -EFAULT; ++ return ret; ++} ++ ++int config_get_device(struct wireguard_device *wg, void __user *udevice) ++{ ++ int ret = 0; ++ struct net_device *dev = netdev_pub(wg); ++ struct data_remaining peer_data = { NULL }; ++ struct wgdevice out_device; ++ struct wgdevice in_device; ++ ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); ++ ++ memset(&out_device, 0, sizeof(struct wgdevice)); ++ ++ mutex_lock(&wg->device_update_lock); ++ ++ if (!udevice) { ++ ret = calculate_peers_size(wg); ++ goto out; ++ } ++ ++ if (copy_from_user(&in_device, udevice, sizeof(in_device))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ out_device.port = wg->incoming_port; ++ out_device.fwmark = wg->fwmark; ++ strncpy(out_device.interface, dev->name, IFNAMSIZ - 1); ++ out_device.interface[IFNAMSIZ - 1] = 0; ++ ++ down_read(&wg->static_identity.lock); ++ if (wg->static_identity.has_identity) { ++ memcpy(out_device.private_key, wg->static_identity.static_private, WG_KEY_LEN); ++ memcpy(out_device.public_key, wg->static_identity.static_public, WG_KEY_LEN); ++ memcpy(out_device.preshared_key, wg->static_identity.preshared_key, WG_KEY_LEN); ++ } ++ up_read(&wg->static_identity.lock); ++ ++ peer_data.out_len = in_device.peers_size; ++ peer_data.data = udevice + sizeof(struct wgdevice); ++ ret = peer_for_each_unlocked(wg, populate_peer, &peer_data); ++ if (ret) ++ goto out; ++ out_device.num_peers = peer_data.count; ++ ++ if (copy_to_user(udevice, &out_device, sizeof(out_device))) ++ ret = -EFAULT; ++ ++out: ++ mutex_unlock(&wg->device_update_lock); ++ memzero_explicit(&out_device.private_key, NOISE_PUBLIC_KEY_LEN); ++ return ret; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/cookie.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,215 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "cookie.h" ++#include "peer.h" ++#include "device.h" ++#include "messages.h" ++#include "crypto/blake2s.h" ++#include "crypto/chacha20poly1305.h" ++ ++#include ++#include ++#include ++ ++int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg) ++{ ++ int ret = ratelimiter_init(&checker->ratelimiter, wg); ++ if (ret) ++ return ret; ++ init_rwsem(&checker->secret_lock); ++ checker->secret_birthdate = get_jiffies_64(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ checker->device = wg; ++ return 0; ++} ++ ++static int precompute_peer_key(struct wireguard_peer *peer, void *psk) ++{ ++ blake2s(peer->latest_cookie.cookie_decryption_key, peer->handshake.remote_static, psk, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, psk ? NOISE_SYMMETRIC_KEY_LEN : 0); ++ return 0; ++} ++ ++void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer) ++{ ++ down_read(&checker->device->static_identity.lock); ++ if (unlikely(checker->device->static_identity.has_identity)) { ++ memset(checker->cookie_encryption_key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ goto out; ++ } ++ ++ if (peer) ++ precompute_peer_key(peer, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ else { ++ blake2s(checker->cookie_encryption_key, checker->device->static_identity.static_public, checker->device->static_identity.preshared_key, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, checker->device->static_identity.has_psk ? NOISE_SYMMETRIC_KEY_LEN : 0); ++ peer_for_each_unlocked(checker->device, precompute_peer_key, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ } ++ ++out: ++ up_read(&checker->device->static_identity.lock); ++} ++ ++void cookie_checker_uninit(struct cookie_checker *checker) ++{ ++ ratelimiter_uninit(&checker->ratelimiter); ++} ++ ++void cookie_init(struct cookie *cookie) ++{ ++ memset(cookie, 0, sizeof(struct cookie)); ++ init_rwsem(&cookie->lock); ++} ++ ++static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ struct blake2s_state state; ++ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac1); ++ ++ if (psk) ++ blake2s_init_key(&state, COOKIE_LEN, psk, NOISE_SYMMETRIC_KEY_LEN); ++ else ++ blake2s_init(&state, COOKIE_LEN); ++ blake2s_update(&state, pubkey, NOISE_PUBLIC_KEY_LEN); ++ blake2s_update(&state, message, len); ++ blake2s_final(&state, mac1, COOKIE_LEN); ++} ++ ++static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len, const u8 cookie[COOKIE_LEN]) ++{ ++ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac2); ++ blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN); ++} ++ ++static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb, struct cookie_checker *checker) ++{ ++ struct blake2s_state state; ++ ++ if (!time_is_after_jiffies64(checker->secret_birthdate + COOKIE_SECRET_MAX_AGE)) { ++ down_write(&checker->secret_lock); ++ checker->secret_birthdate = get_jiffies_64(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ up_write(&checker->secret_lock); ++ } ++ ++ down_read(&checker->secret_lock); ++ ++ blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN); ++ if (ip_hdr(skb)->version == 4) ++ blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr, sizeof(struct in_addr)); ++ else if (ip_hdr(skb)->version == 6) ++ blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr, sizeof(struct in6_addr)); ++ blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16)); ++ blake2s_final(&state, cookie, COOKIE_LEN); ++ ++ up_read(&checker->secret_lock); ++} ++ ++enum cookie_mac_state cookie_validate_packet(struct cookie_checker *checker, struct sk_buff *skb, void *data_start, size_t data_len, bool check_cookie) ++{ ++ u8 computed_mac[COOKIE_LEN]; ++ u8 cookie[COOKIE_LEN]; ++ enum cookie_mac_state ret; ++ struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs)); ++ ++ ret = INVALID_MAC; ++ down_read(&checker->device->static_identity.lock); ++ if (unlikely(!checker->device->static_identity.has_identity)) { ++ up_read(&checker->device->static_identity.lock); ++ goto out; ++ } ++ compute_mac1(computed_mac, data_start, data_len, checker->device->static_identity.static_public, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ up_read(&checker->device->static_identity.lock); ++ if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_BUT_NO_COOKIE; ++ ++ if (!check_cookie) ++ goto out; ++ ++ make_cookie(cookie, skb, checker); ++ ++ compute_mac2(computed_mac, data_start, data_len, cookie); ++ if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED; ++ if (!ratelimiter_allow(&checker->ratelimiter, skb)) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE; ++ ++out: ++ return ret; ++} ++ ++void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer) ++{ ++ struct message_macs *macs = (struct message_macs *)((u8 *)message + len - sizeof(struct message_macs)); ++ ++ down_read(&peer->device->static_identity.lock); ++ if (unlikely(!peer->device->static_identity.has_identity)) { ++ memset(macs, 0, sizeof(struct message_macs)); ++ up_read(&peer->device->static_identity.lock); ++ return; ++ } ++ compute_mac1(macs->mac1, message, len, peer->handshake.remote_static, peer->device->static_identity.has_psk ? peer->device->static_identity.preshared_key : NULL); ++ up_read(&peer->device->static_identity.lock); ++ ++ down_write(&peer->latest_cookie.lock); ++ memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN); ++ peer->latest_cookie.have_sent_mac1 = true; ++ up_write(&peer->latest_cookie.lock); ++ ++ down_read(&peer->latest_cookie.lock); ++ if (peer->latest_cookie.is_valid && time_is_after_jiffies64(peer->latest_cookie.birthdate + COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY)) ++ compute_mac2(macs->mac2, message, len, peer->latest_cookie.cookie); ++ else ++ memset(macs->mac2, 0, COOKIE_LEN); ++ up_read(&peer->latest_cookie.lock); ++} ++ ++void cookie_message_create(struct message_handshake_cookie *dst, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker) ++{ ++ struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs)); ++ u8 cookie[COOKIE_LEN]; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE); ++ dst->receiver_index = index; ++ get_random_bytes(dst->nonce, COOKIE_NONCE_LEN); ++ blake2s(dst->nonce, dst->nonce, NULL, COOKIE_NONCE_LEN, COOKIE_NONCE_LEN, 0); /* Avoid directly transmitting RNG output. */ ++ ++ make_cookie(cookie, skb, checker); ++ xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, macs->mac1, COOKIE_LEN, dst->nonce, checker->cookie_encryption_key); ++} ++ ++void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg) ++{ ++ u8 cookie[COOKIE_LEN]; ++ struct index_hashtable_entry *entry; ++ bool ret; ++ ++ entry = index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE | INDEX_HASHTABLE_KEYPAIR, src->receiver_index); ++ if (!unlikely(entry)) ++ return; ++ ++ down_read(&entry->peer->latest_cookie.lock); ++ if (unlikely(!entry->peer->latest_cookie.have_sent_mac1)) { ++ up_read(&entry->peer->latest_cookie.lock); ++ goto out; ++ } ++ ret = xchacha20poly1305_decrypt(cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie), entry->peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce, entry->peer->latest_cookie.cookie_decryption_key); ++ up_read(&entry->peer->latest_cookie.lock); ++ ++ if (ret) { ++ down_write(&entry->peer->latest_cookie.lock); ++ memcpy(entry->peer->latest_cookie.cookie, cookie, COOKIE_LEN); ++ entry->peer->latest_cookie.birthdate = get_jiffies_64(); ++ entry->peer->latest_cookie.is_valid = true; ++ entry->peer->latest_cookie.have_sent_mac1 = false; ++ up_write(&entry->peer->latest_cookie.lock); ++ } else ++ net_dbg_ratelimited("Could not decrypt invalid cookie response\n"); ++ ++out: ++ peer_put(entry->peer); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/data.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,493 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "noise.h" ++#include "device.h" ++#include "peer.h" ++#include "messages.h" ++#include "packets.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct encryption_skb_cb { ++ u8 ds; ++ u8 num_frags; ++ unsigned int plaintext_len, trailer_len; ++ struct sk_buff *trailer; ++ u64 nonce; ++}; ++ ++struct encryption_ctx { ++ struct padata_priv padata; ++ struct sk_buff_head queue; ++ packet_create_data_callback_t callback; ++ struct wireguard_peer *peer; ++ struct noise_keypair *keypair; ++}; ++ ++struct decryption_ctx { ++ struct padata_priv padata; ++ struct sk_buff *skb; ++ packet_consume_data_callback_t callback; ++ struct noise_keypair *keypair; ++ struct endpoint endpoint; ++ u64 nonce; ++ int ret; ++ u8 num_frags; ++}; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static struct kmem_cache *encryption_ctx_cache __read_mostly; ++static struct kmem_cache *decryption_ctx_cache __read_mostly; ++ ++int packet_init_data_caches(void) ++{ ++ BUILD_BUG_ON(sizeof(struct encryption_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); ++ encryption_ctx_cache = kmem_cache_create("wireguard_encryption_ctx", sizeof(struct encryption_ctx), 0, 0, NULL); ++ if (!encryption_ctx_cache) ++ return -ENOMEM; ++ decryption_ctx_cache = kmem_cache_create("wireguard_decryption_ctx", sizeof(struct decryption_ctx), 0, 0, NULL); ++ if (!decryption_ctx_cache) { ++ kmem_cache_destroy(encryption_ctx_cache); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void packet_deinit_data_caches(void) ++{ ++ kmem_cache_destroy(encryption_ctx_cache); ++ kmem_cache_destroy(decryption_ctx_cache); ++} ++#endif ++ ++/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */ ++static inline bool counter_validate(union noise_counter *counter, u64 their_counter) ++{ ++ bool ret = false; ++ unsigned long index, index_current, top, i; ++ spin_lock_bh(&counter->receive.lock); ++ ++ if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || their_counter >= REJECT_AFTER_MESSAGES)) ++ goto out; ++ ++ ++their_counter; ++ ++ if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < counter->receive.counter)) ++ goto out; ++ ++ index = their_counter >> ilog2(COUNTER_REDUNDANT_BITS); ++ ++ if (likely(their_counter > counter->receive.counter)) { ++ index_current = counter->receive.counter >> ilog2(COUNTER_REDUNDANT_BITS); ++ top = min_t(unsigned long, index - index_current, COUNTER_BITS_TOTAL / BITS_PER_LONG); ++ for (i = 1; i <= top; ++i) ++ counter->receive.backtrack[(i + index_current) & ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; ++ counter->receive.counter = their_counter; ++ } ++ ++ index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; ++ ret = !test_and_set_bit(their_counter & (COUNTER_REDUNDANT_BITS - 1), &counter->receive.backtrack[index]); ++ ++out: ++ spin_unlock_bh(&counter->receive.lock); ++ return ret; ++} ++#include "selftest/counter.h" ++ ++static inline unsigned int skb_padding(struct sk_buff *skb) ++{ ++ /* We do this modulo business with the MTU, just in case the networking layer ++ * gives us a packet that's bigger than the MTU. Now that we support GSO, this ++ * shouldn't be a real problem, and this can likely be removed. But, caution! */ ++ unsigned int last_unit = skb->len % skb->dev->mtu; ++ unsigned int padded_size = (last_unit + MESSAGE_PADDING_MULTIPLE - 1) & ~(MESSAGE_PADDING_MULTIPLE - 1); ++ if (padded_size > skb->dev->mtu) ++ padded_size = skb->dev->mtu; ++ return padded_size - last_unit; ++} ++ ++static inline void skb_reset(struct sk_buff *skb) ++{ ++ skb_scrub_packet(skb, false); ++ memset(&skb->headers_start, 0, offsetof(struct sk_buff, headers_end) - offsetof(struct sk_buff, headers_start)); ++ skb->queue_mapping = 0; ++ skb->nohdr = 0; ++ skb->peeked = 0; ++ skb->mac_len = 0; ++ skb->dev = NULL; ++#ifdef CONFIG_NET_SCHED ++ skb->tc_index = 0; ++ skb_reset_tc(skb); ++#endif ++ skb->hdr_len = skb_headroom(skb); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ skb_probe_transport_header(skb, 0); ++} ++ ++static inline void skb_encrypt(struct sk_buff *skb, struct noise_keypair *keypair, bool have_simd) ++{ ++ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb; ++ struct scatterlist sg[cb->num_frags]; /* This should be bound to at most 128 by the caller. */ ++ struct message_data *header; ++ ++ /* We have to remember to add the checksum to the innerpacket, in case the receiver forwards it. */ ++ if (likely(!skb_checksum_setup(skb, true))) ++ skb_checksum_help(skb); ++ ++ /* Only after checksumming can we safely add on the padding at the end and the header. */ ++ header = (struct message_data *)skb_push(skb, sizeof(struct message_data)); ++ header->header.type = cpu_to_le32(MESSAGE_DATA); ++ header->key_idx = keypair->remote_index; ++ header->counter = cpu_to_le64(cb->nonce); ++ pskb_put(skb, cb->trailer, cb->trailer_len); ++ ++ /* Now we can encrypt the scattergather segments */ ++ sg_init_table(sg, cb->num_frags); ++ skb_to_sgvec(skb, sg, sizeof(struct message_data), noise_encrypted_len(cb->plaintext_len)); ++ chacha20poly1305_encrypt_sg(sg, sg, cb->plaintext_len, NULL, 0, cb->nonce, keypair->sending.key, have_simd); ++} ++ ++static inline bool skb_decrypt(struct sk_buff *skb, u8 num_frags, u64 nonce, struct noise_symmetric_key *key) ++{ ++ struct scatterlist sg[num_frags]; /* This should be bound to at most 128 by the caller. */ ++ ++ if (unlikely(!key)) ++ return false; ++ ++ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME) || key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ sg_init_table(sg, num_frags); ++ skb_to_sgvec(skb, sg, 0, skb->len); ++ ++ if (!chacha20poly1305_decrypt_sg(sg, sg, skb->len, NULL, 0, nonce, key->key)) ++ return false; ++ ++ return pskb_trim(skb, skb->len - noise_encrypted_len(0)) == 0; ++} ++ ++static inline bool get_encryption_nonce(u64 *nonce, struct noise_symmetric_key *key) ++{ ++ if (unlikely(!key)) ++ return false; ++ ++ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME))) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ *nonce = atomic64_inc_return(&key->counter.counter) - 1; ++ if (*nonce >= REJECT_AFTER_MESSAGES) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void queue_encrypt_reset(struct sk_buff_head *queue, struct noise_keypair *keypair) ++{ ++ struct sk_buff *skb; ++ bool have_simd = chacha20poly1305_init_simd(); ++ skb_queue_walk(queue, skb) { ++ skb_encrypt(skb, keypair, have_simd); ++ skb_reset(skb); ++ } ++ chacha20poly1305_deinit_simd(have_simd); ++ noise_keypair_put(keypair); ++} ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static void do_encryption(struct padata_priv *padata) ++{ ++ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata); ++ ++ queue_encrypt_reset(&ctx->queue, ctx->keypair); ++ padata_do_serial(padata); ++} ++ ++static void finish_encryption(struct padata_priv *padata) ++{ ++ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata); ++ ++ ctx->callback(&ctx->queue, ctx->peer); ++ atomic_dec(&ctx->peer->parallel_encryption_inflight); ++ peer_put(ctx->peer); ++ kmem_cache_free(encryption_ctx_cache, ctx); ++} ++ ++static inline int start_encryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu) ++{ ++ memset(priv, 0, sizeof(struct padata_priv)); ++ priv->parallel = do_encryption; ++ priv->serial = finish_encryption; ++ return padata_do_parallel(padata, priv, cb_cpu); ++} ++ ++static inline unsigned int choose_cpu(__le32 key) ++{ ++ unsigned int cpu_index, cpu, cb_cpu; ++ ++ /* This ensures that packets encrypted to the same key are sent in-order. */ ++ cpu_index = ((__force unsigned int)key) % cpumask_weight(cpu_online_mask); ++ cb_cpu = cpumask_first(cpu_online_mask); ++ for (cpu = 0; cpu < cpu_index; ++cpu) ++ cb_cpu = cpumask_next(cb_cpu, cpu_online_mask); ++ ++ return cb_cpu; ++} ++#endif ++ ++int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback) ++{ ++ int ret = -ENOKEY; ++ struct noise_keypair *keypair; ++ struct sk_buff *skb; ++ ++ rcu_read_lock(); ++ keypair = noise_keypair_get(rcu_dereference(peer->keypairs.current_keypair)); ++ if (unlikely(!keypair)) ++ goto err_rcu; ++ rcu_read_unlock(); ++ ++ skb_queue_walk(queue, skb) { ++ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb; ++ unsigned int padding_len, num_frags; ++ ++ if (unlikely(!get_encryption_nonce(&cb->nonce, &keypair->sending))) ++ goto err; ++ ++ padding_len = skb_padding(skb); ++ cb->trailer_len = padding_len + noise_encrypted_len(0); ++ cb->plaintext_len = skb->len + padding_len; ++ ++ /* Store the ds bit in the cb */ ++ cb->ds = ip_tunnel_ecn_encap(0 /* No outer TOS: no leak. TODO: should we use flowi->tos as outer? */, ip_hdr(skb), skb); ++ ++ /* Expand data section to have room for padding and auth tag */ ++ ret = skb_cow_data(skb, cb->trailer_len, &cb->trailer); ++ if (unlikely(ret < 0)) ++ goto err; ++ num_frags = ret; ++ ret = -ENOMEM; ++ if (unlikely(num_frags > 128)) ++ goto err; ++ cb->num_frags = num_frags; ++ ++ /* Set the padding to zeros, and make sure it and the auth tag are part of the skb */ ++ memset(skb_tail_pointer(cb->trailer), 0, padding_len); ++ ++ /* Expand head section to have room for our header and the network stack's headers. */ ++ ret = skb_cow_head(skb, DATA_PACKET_HEAD_ROOM); ++ if (unlikely(ret < 0)) ++ goto err; ++ ++ /* After the first time through the loop, if we've suceeded with a legitimate nonce, ++ * then we don't want a -ENOKEY error if subsequent nonces fail. Rather, if this ++ * condition arises, we simply want error out hard, and drop the entire queue. This ++ * is partially lazy programming and TODO: this could be made to only requeue the ++ * ones that had no nonce. But I'm not sure it's worth the added complexity, given ++ * how rarely that condition should arise. */ ++ ret = -EPIPE; ++ } ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ if ((skb_queue_len(queue) > 1 || queue->next->len > 256 || atomic_read(&peer->parallel_encryption_inflight) > 0) && cpumask_weight(cpu_online_mask) > 1) { ++ unsigned int cpu = choose_cpu(keypair->remote_index); ++ struct encryption_ctx *ctx = kmem_cache_alloc(encryption_ctx_cache, GFP_ATOMIC); ++ if (!ctx) ++ goto serial_encrypt; ++ skb_queue_head_init(&ctx->queue); ++ skb_queue_splice_init(queue, &ctx->queue); ++ ctx->callback = callback; ++ ctx->keypair = keypair; ++ ctx->peer = peer_rcu_get(peer); ++ ret = -EBUSY; ++ if (unlikely(!ctx->peer)) ++ goto err_parallel; ++ atomic_inc(&peer->parallel_encryption_inflight); ++ ret = start_encryption(peer->device->parallel_send, &ctx->padata, cpu); ++ if (unlikely(ret < 0)) { ++ atomic_dec(&peer->parallel_encryption_inflight); ++ peer_put(ctx->peer); ++err_parallel: ++ skb_queue_splice(&ctx->queue, queue); ++ kmem_cache_free(encryption_ctx_cache, ctx); ++ goto err; ++ } ++ } else ++serial_encrypt: ++#endif ++ { ++ queue_encrypt_reset(queue, keypair); ++ callback(queue, peer); ++ } ++ return 0; ++ ++err: ++ noise_keypair_put(keypair); ++ return ret; ++err_rcu: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static void begin_decrypt_packet(struct decryption_ctx *ctx) ++{ ++ if (unlikely(!skb_decrypt(ctx->skb, ctx->num_frags, ctx->nonce, &ctx->keypair->receiving))) ++ goto err; ++ ++ skb_reset(ctx->skb); ++ ctx->ret = 0; ++ return; ++ ++err: ++ ctx->ret = -ENOKEY; ++ peer_put(ctx->keypair->entry.peer); ++} ++ ++static void finish_decrypt_packet(struct decryption_ctx *ctx) ++{ ++ struct noise_keypairs *keypairs; ++ bool used_new_key = false; ++ int ret = ctx->ret; ++ if (ret) ++ goto err; ++ ++ keypairs = &ctx->keypair->entry.peer->keypairs; ++ ret = counter_validate(&ctx->keypair->receiving.counter, ctx->nonce) ? 0 : -ERANGE; ++ ++ if (likely(!ret)) ++ used_new_key = noise_received_with_keypair(&ctx->keypair->entry.peer->keypairs, ctx->keypair); ++ else { ++ net_dbg_ratelimited("Packet has invalid nonce %Lu (max %Lu)\n", ctx->nonce, ctx->keypair->receiving.counter.receive.counter); ++ peer_put(ctx->keypair->entry.peer); ++ goto err; ++ } ++ ++ noise_keypair_put(ctx->keypair); ++ ctx->callback(ctx->skb, ctx->keypair->entry.peer, &ctx->endpoint, used_new_key, 0); ++ return; ++ ++err: ++ noise_keypair_put(ctx->keypair); ++ ctx->callback(ctx->skb, NULL, NULL, false, ret); ++} ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static void do_decryption(struct padata_priv *padata) ++{ ++ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata); ++ begin_decrypt_packet(ctx); ++ padata_do_serial(padata); ++} ++ ++static void finish_decryption(struct padata_priv *padata) ++{ ++ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata); ++ finish_decrypt_packet(ctx); ++ kmem_cache_free(decryption_ctx_cache, ctx); ++} ++ ++static inline int start_decryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu) ++{ ++ priv->parallel = do_decryption; ++ priv->serial = finish_decryption; ++ return padata_do_parallel(padata, priv, cb_cpu); ++} ++#endif ++ ++void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback) ++{ ++ int ret; ++ struct endpoint endpoint; ++ unsigned int num_frags; ++ struct sk_buff *trailer; ++ struct message_data *header; ++ struct noise_keypair *keypair; ++ u64 nonce; ++ __le32 idx; ++ ++ ret = socket_endpoint_from_skb(&endpoint, skb); ++ if (unlikely(ret < 0)) ++ goto err; ++ ++ ret = -ENOMEM; ++ if (unlikely(!pskb_may_pull(skb, offset + sizeof(struct message_data)))) ++ goto err; ++ ++ header = (struct message_data *)(skb->data + offset); ++ offset += sizeof(struct message_data); ++ skb_pull(skb, offset); ++ ++ idx = header->key_idx; ++ nonce = le64_to_cpu(header->counter); ++ ++ ret = skb_cow_data(skb, 0, &trailer); ++ if (unlikely(ret < 0)) ++ goto err; ++ num_frags = ret; ++ ret = -ENOMEM; ++ if (unlikely(num_frags > 128)) ++ goto err; ++ ret = -EINVAL; ++ rcu_read_lock(); ++ keypair = noise_keypair_get((struct noise_keypair *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_KEYPAIR, idx)); ++ rcu_read_unlock(); ++ if (unlikely(!keypair)) ++ goto err; ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ if (cpumask_weight(cpu_online_mask) > 1) { ++ unsigned int cpu = choose_cpu(idx); ++ struct decryption_ctx *ctx; ++ ++ ret = -ENOMEM; ++ ctx = kmem_cache_alloc(decryption_ctx_cache, GFP_ATOMIC); ++ if (unlikely(!ctx)) ++ goto err_peer; ++ ++ ctx->skb = skb; ++ ctx->keypair = keypair; ++ ctx->callback = callback; ++ ctx->nonce = nonce; ++ ctx->num_frags = num_frags; ++ ctx->endpoint = endpoint; ++ ret = start_decryption(wg->parallel_receive, &ctx->padata, cpu); ++ if (unlikely(ret)) { ++ kmem_cache_free(decryption_ctx_cache, ctx); ++ goto err_peer; ++ } ++ } else ++#endif ++ { ++ struct decryption_ctx ctx = { ++ .skb = skb, ++ .keypair = keypair, ++ .callback = callback, ++ .nonce = nonce, ++ .num_frags = num_frags, ++ .endpoint = endpoint ++ }; ++ begin_decrypt_packet(&ctx); ++ finish_decrypt_packet(&ctx); ++ } ++ return; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++err_peer: ++ peer_put(keypair->entry.peer); ++ noise_keypair_put(keypair); ++#endif ++err: ++ callback(skb, NULL, NULL, false, ret); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/device.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,387 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "socket.h" ++#include "timers.h" ++#include "device.h" ++#include "config.h" ++#include "peer.h" ++#include "uapi.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++#include ++#include ++#endif ++ ++static int open_peer(struct wireguard_peer *peer, void *data) ++{ ++ timers_init_peer(peer); ++ packet_send_queue(peer); ++ if (peer->persistent_keepalive_interval) ++ packet_send_keepalive(peer); ++ return 0; ++} ++ ++static int open(struct net_device *dev) ++{ ++ int ret; ++ struct wireguard_device *wg = netdev_priv(dev); ++ struct inet6_dev *dev_v6 = __in6_dev_get(dev); ++ struct in_device *dev_v4 = __in_dev_get_rtnl(dev); ++ ++ if (dev_v4) { ++ /* TODO: when we merge to mainline, put this check near the ip_rt_send_redirect ++ * call of ip_forward in net/ipv4/ip_forward.c, similar to the current secpath ++ * check, rather than turning it off like this. This is just a stop gap solution ++ * while we're an out of tree module. */ ++ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); ++ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false; ++ } ++ if (dev_v6) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++ dev_v6->addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; ++#else ++ dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; ++#endif ++ ++ ret = socket_init(wg); ++ if (ret < 0) ++ return ret; ++ peer_for_each(wg, open_peer, NULL); ++ return 0; ++} ++ ++static int clear_noise_peer(struct wireguard_peer *peer, void *data) ++{ ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ if (peer->timers_enabled) ++ del_timer(&peer->timer_kill_ephemerals); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int suspending_clear_noise_peers(struct notifier_block *nb, unsigned long action, void *data) ++{ ++ struct wireguard_device *wg = container_of(nb, struct wireguard_device, clear_peers_on_suspend); ++ if (action == PM_HIBERNATION_PREPARE || action == PM_SUSPEND_PREPARE) { ++ peer_for_each(wg, clear_noise_peer, NULL); ++ rcu_barrier(); ++ } ++ return 0; ++} ++#endif ++ ++static int stop_peer(struct wireguard_peer *peer, void *data) ++{ ++ timers_uninit_peer(peer); ++ clear_noise_peer(peer, data); ++ return 0; ++} ++ ++static int stop(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ peer_for_each(wg, stop_peer, NULL); ++ skb_queue_purge(&wg->incoming_handshakes); ++ socket_uninit(wg); ++ return 0; ++} ++ ++static void skb_unsendable(struct sk_buff *skb, struct net_device *dev) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ /* This conntrack stuff is because the rate limiting needs to be applied ++ * to the original src IP, so we have to restore saddr in the IP header. ++ * It's not needed if conntracking isn't in the kernel, because in that ++ * case the saddr wouldn't be NAT-transformed anyway. */ ++ enum ip_conntrack_info ctinfo; ++ struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++#endif ++ ++dev->stats.tx_errors; ++ ++ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) { ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ if (ct) ++ ip_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.ip; ++#endif ++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); ++ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) { ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ if (ct) ++ ipv6_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.in6; ++#endif ++ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); ++ } ++ kfree_skb(skb); ++} ++ ++static netdev_tx_t xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ struct wireguard_peer *peer; ++ int ret; ++ ++ if (unlikely(dev_recursion_level() > 4)) { ++ ret = -ELOOP; ++ net_dbg_ratelimited("Routing loop detected\n"); ++ skb_unsendable(skb, dev); ++ goto err; ++ } ++ ++ peer = routing_table_lookup_dst(&wg->peer_routing_table, skb); ++ if (unlikely(!peer)) { ++ ret = -ENOKEY; ++ net_dbg_skb_ratelimited("No peer is configured for %pISc\n", skb); ++ goto err; ++ } ++ ++ read_lock_bh(&peer->endpoint_lock); ++ ret = peer->endpoint.addr.sa_family != AF_INET && peer->endpoint.addr.sa_family != AF_INET6; ++ read_unlock_bh(&peer->endpoint_lock); ++ if (unlikely(ret)) { ++ ret = -EHOSTUNREACH; ++ net_dbg_ratelimited("No valid endpoint has been configured or discovered for peer %Lu\n", peer->internal_id); ++ goto err_peer; ++ } ++ ++ /* If the queue is getting too big, we start removing the oldest packets until it's small again. ++ * We do this before adding the new packet, so we don't remove GSO segments that are in excess. */ ++ while (skb_queue_len(&peer->tx_packet_queue) > MAX_QUEUED_OUTGOING_PACKETS) ++ dev_kfree_skb(skb_dequeue(&peer->tx_packet_queue)); ++ ++ if (!skb_is_gso(skb)) ++ skb->next = NULL; ++ else { ++ struct sk_buff *segs = skb_gso_segment(skb, 0); ++ if (unlikely(IS_ERR(segs))) { ++ ret = PTR_ERR(segs); ++ goto err_peer; ++ } ++ dev_kfree_skb(skb); ++ skb = segs; ++ } ++ while (skb) { ++ struct sk_buff *next = skb->next; ++ skb->next = skb->prev = NULL; ++ ++ skb = skb_share_check(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ continue; ++ ++ /* We only need to keep the original dst around for icmp, ++ * so at this point we're in a position to drop it. */ ++ skb_dst_drop(skb); ++ ++ skb_queue_tail(&peer->tx_packet_queue, skb); ++ skb = next; ++ } ++ ++ packet_send_queue(peer); ++ peer_put(peer); ++ return NETDEV_TX_OK; ++ ++err_peer: ++ peer_put(peer); ++err: ++ skb_unsendable(skb, dev); ++ return ret; ++} ++ ++ ++static int ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ switch (cmd) { ++ case WG_GET_DEVICE: ++ return config_get_device(wg, ifr->ifr_ifru.ifru_data); ++ case WG_SET_DEVICE: ++ return config_set_device(wg, ifr->ifr_ifru.ifru_data); ++ } ++ return -EINVAL; ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_open = open, ++ .ndo_stop = stop, ++ .ndo_start_xmit = xmit, ++ .ndo_get_stats64 = ip_tunnel_get_stats64, ++ .ndo_do_ioctl = ioctl ++}; ++ ++static void destruct(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ mutex_lock(&wg->device_update_lock); ++ peer_remove_all(wg); ++ wg->incoming_port = 0; ++ destroy_workqueue(wg->workqueue); ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ padata_free(wg->parallel_send); ++ padata_free(wg->parallel_receive); ++ destroy_workqueue(wg->parallelqueue); ++#endif ++ routing_table_free(&wg->peer_routing_table); ++ memzero_explicit(&wg->static_identity, sizeof(struct noise_static_identity)); ++ skb_queue_purge(&wg->incoming_handshakes); ++ socket_uninit(wg); ++ cookie_checker_uninit(&wg->cookie_checker); ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&wg->clear_peers_on_suspend); ++#endif ++ mutex_unlock(&wg->device_update_lock); ++ free_percpu(dev->tstats); ++ ++ put_net(wg->creating_net); ++ ++ pr_debug("Device %s has been deleted\n", dev->name); ++ free_netdev(dev); ++} ++ ++static void setup(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA }; ++ ++ dev->netdev_ops = &netdev_ops; ++ dev->destructor = destruct; ++ dev->hard_header_len = 0; ++ dev->addr_len = 0; ++ dev->needed_headroom = DATA_PACKET_HEAD_ROOM; ++ dev->needed_tailroom = noise_encrypted_len(MESSAGE_PADDING_MULTIPLE); ++ dev->type = ARPHRD_NONE; ++ dev->flags = IFF_POINTOPOINT | IFF_NOARP; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) ++ dev->flags |= IFF_NO_QUEUE; ++#else ++ dev->tx_queue_len = 0; ++#endif ++ dev->features |= NETIF_F_LLTX; ++ dev->features |= WG_NETDEV_FEATURES; ++ dev->hw_features |= WG_NETDEV_FEATURES; ++ dev->hw_enc_features |= WG_NETDEV_FEATURES; ++ dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH - sizeof(struct udphdr) - max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); ++ ++ /* We need to keep the dst around in case of icmp replies. */ ++ netif_keep_dst(dev); ++ ++ memset(wg, 0, sizeof(struct wireguard_device)); ++} ++ ++static int newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) ++{ ++ int ret = -ENOMEM; ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ wg->creating_net = get_net(src_net); ++ init_rwsem(&wg->static_identity.lock); ++ mutex_init(&wg->socket_update_lock); ++ mutex_init(&wg->device_update_lock); ++ skb_queue_head_init(&wg->incoming_handshakes); ++ INIT_WORK(&wg->incoming_handshakes_work, packet_process_queued_handshake_packets); ++ pubkey_hashtable_init(&wg->peer_hashtable); ++ index_hashtable_init(&wg->index_hashtable); ++ routing_table_init(&wg->peer_routing_table); ++ INIT_LIST_HEAD(&wg->peer_list); ++ ++ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); ++ if (!dev->tstats) ++ goto error_1; ++ ++ wg->workqueue = alloc_workqueue("wg-%s", WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name); ++ if (!wg->workqueue) ++ goto error_2; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ wg->parallelqueue = alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, dev->name); ++ if (!wg->parallelqueue) ++ goto error_3; ++ ++ wg->parallel_send = padata_alloc_possible(wg->parallelqueue); ++ if (!wg->parallel_send) ++ goto error_4; ++ padata_start(wg->parallel_send); ++ ++ wg->parallel_receive = padata_alloc_possible(wg->parallelqueue); ++ if (!wg->parallel_receive) ++ goto error_5; ++ padata_start(wg->parallel_receive); ++#endif ++ ++ ret = cookie_checker_init(&wg->cookie_checker, wg); ++ if (ret < 0) ++ goto error_6; ++ ++#ifdef CONFIG_PM_SLEEP ++ wg->clear_peers_on_suspend.notifier_call = suspending_clear_noise_peers; ++ ret = register_pm_notifier(&wg->clear_peers_on_suspend); ++ if (ret < 0) ++ goto error_7; ++#endif ++ ++ ret = register_netdevice(dev); ++ if (ret < 0) ++ goto error_8; ++ ++ pr_debug("Device %s has been created\n", dev->name); ++ ++ return 0; ++ ++error_8: ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&wg->clear_peers_on_suspend); ++error_7: ++#endif ++ cookie_checker_uninit(&wg->cookie_checker); ++error_6: ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ padata_free(wg->parallel_receive); ++error_5: ++ padata_free(wg->parallel_send); ++error_4: ++ destroy_workqueue(wg->parallelqueue); ++error_3: ++#endif ++ destroy_workqueue(wg->workqueue); ++error_2: ++ free_percpu(dev->tstats); ++error_1: ++ put_net(src_net); ++ return ret; ++} ++ ++static struct rtnl_link_ops link_ops __read_mostly = { ++ .kind = KBUILD_MODNAME, ++ .priv_size = sizeof(struct wireguard_device), ++ .setup = setup, ++ .newlink = newlink, ++}; ++ ++int device_init(void) ++{ ++ return rtnl_link_register(&link_ops); ++} ++ ++void device_uninit(void) ++{ ++ rtnl_link_unregister(&link_ops); ++ rcu_barrier(); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/hashtables.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,136 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "hashtables.h" ++#include "peer.h" ++#include "noise.h" ++ ++static inline struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ /* siphash gives us a secure 64bit number based on a random key. Since the bits are ++ * uniformly distributed, we can then mask off to get the bits we need. */ ++ return &table->hashtable[siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key) & (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++void pubkey_hashtable_init(struct pubkey_hashtable *table) ++{ ++ get_random_bytes(&table->key, sizeof(table->key)); ++ hash_init(table->hashtable); ++ mutex_init(&table->lock); ++} ++ ++void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_add_head_rcu(&peer->pubkey_hash, pubkey_bucket(table, peer->handshake.remote_static)); ++ mutex_unlock(&table->lock); ++} ++ ++void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_del_init_rcu(&peer->pubkey_hash); ++ mutex_unlock(&table->lock); ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ struct wireguard_peer *iter_peer, *peer = NULL; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(iter_peer, pubkey_bucket(table, pubkey), pubkey_hash) { ++ if (!memcmp(pubkey, iter_peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN)) { ++ peer = iter_peer; ++ break; ++ } ++ } ++ peer = peer_get(peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++static inline struct hlist_head *index_bucket(struct index_hashtable *table, const __le32 index) ++{ ++ /* Since the indices are random and thus all bits are uniformly distributed, ++ * we can find its bucket simply by masking. */ ++ return &table->hashtable[(__force u32)index & (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++void index_hashtable_init(struct index_hashtable *table) ++{ ++ get_random_bytes(&table->key, sizeof(table->key)); ++ hash_init(table->hashtable); ++ spin_lock_init(&table->lock); ++} ++ ++__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry) ++{ ++ struct index_hashtable_entry *existing_entry; ++ u32 counter = get_random_int(); ++ ++ spin_lock(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock(&table->lock); ++ ++ rcu_read_lock(); ++ ++search_unused_slot: ++ /* First we try to find an unused slot, randomly, while unlocked. */ ++ entry->index = (__force __le32)siphash_2u32(get_random_int(), counter++, &table->key); ++ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) { ++ if (existing_entry->index == entry->index) ++ goto search_unused_slot; /* If it's already in use, we continue searching. */ ++ } ++ ++ /* Once we've found an unused slot, we lock it, and then double-check ++ * that nobody else stole it from us. */ ++ spin_lock(&table->lock); ++ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) { ++ if (existing_entry->index == entry->index) { ++ spin_unlock(&table->lock); ++ goto search_unused_slot; /* If it was stolen, we start over. */ ++ } ++ } ++ /* Otherwise, we know we have it exclusively (since we're locked), so we insert. */ ++ hlist_add_head_rcu(&entry->index_hash, index_bucket(table, entry->index)); ++ spin_unlock(&table->lock); ++ ++ rcu_read_unlock(); ++ ++ return entry->index; ++} ++ ++void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new) ++{ ++ spin_lock(&table->lock); ++ new->index = old->index; ++ hlist_replace_rcu(&old->index_hash, &new->index_hash); ++ INIT_HLIST_NODE(&old->index_hash); ++ spin_unlock(&table->lock); ++} ++ ++void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry) ++{ ++ spin_lock(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock(&table->lock); ++} ++ ++/* Returns a strong reference to a entry->peer */ ++struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index) ++{ ++ struct index_hashtable_entry *iter_entry, *entry = NULL; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(iter_entry, index_bucket(table, index), index_hash) { ++ if (iter_entry->index == index && (iter_entry->type & type_mask)) { ++ entry = iter_entry; ++ break; ++ } ++ } ++ if (likely(entry)) { ++ entry->peer = peer_get(entry->peer); ++ if (unlikely(!entry->peer)) ++ entry = NULL; ++ } ++ rcu_read_unlock(); ++ return entry; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/main.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,70 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "version.h" ++#include "device.h" ++#include "noise.h" ++#include "packets.h" ++#include "crypto/chacha20poly1305.h" ++#include "crypto/blake2s.h" ++#include "crypto/curve25519.h" ++ ++#include ++#include ++#include ++#include ++ ++static int __init mod_init(void) ++{ ++ int ret; ++ ++#ifdef DEBUG ++ if (!routing_table_selftest() || !packet_counter_selftest() || !curve25519_selftest() || !chacha20poly1305_selftest() || !blake2s_selftest()) ++ return -ENOTRECOVERABLE; ++#endif ++ chacha20poly1305_init(); ++ noise_init(); ++ ++ ret = ratelimiter_module_init(); ++ if (ret < 0) ++ return ret; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ ret = packet_init_data_caches(); ++ if (ret < 0) ++ goto err_packet; ++#endif ++ ++ ret = device_init(); ++ if (ret < 0) ++ goto err_device; ++ ++ pr_info("WireGuard " WIREGUARD_VERSION " loaded. See www.wireguard.io for information.\n"); ++ pr_info("Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved.\n"); ++ ++ return 0; ++ ++err_device: ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ packet_deinit_data_caches(); ++err_packet: ++#endif ++ ratelimiter_module_deinit(); ++ return ret; ++} ++ ++static void __exit mod_exit(void) ++{ ++ device_uninit(); ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ packet_deinit_data_caches(); ++#endif ++ ratelimiter_module_deinit(); ++ pr_debug("WireGuard has been unloaded\n"); ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Fast, secure, and modern VPN tunnel"); ++MODULE_AUTHOR("Jason A. Donenfeld "); ++MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME); +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/noise.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,593 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "noise.h" ++#include "device.h" ++#include "peer.h" ++#include "messages.h" ++#include "packets.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* This implements Noise_IK: ++ * ++ * <- s ++ * ****** ++ * -> e, es, s, ss, t ++ * <- e, ee, se ++ */ ++ ++static const u8 handshake_name[33] = "Noise_IK_25519_ChaChaPoly_BLAKE2s"; ++static const u8 handshake_psk_name[36] = "NoisePSK_IK_25519_ChaChaPoly_BLAKE2s"; ++static u8 handshake_name_hash[NOISE_HASH_LEN] __read_mostly; ++static u8 handshake_psk_name_hash[NOISE_HASH_LEN] __read_mostly; ++static const u8 identifier_name[34] = "WireGuard v0 zx2c4 Jason@zx2c4.com"; ++static atomic64_t keypair_counter = ATOMIC64_INIT(0); ++ ++void noise_init(void) ++{ ++ blake2s(handshake_name_hash, handshake_name, NULL, NOISE_HASH_LEN, sizeof(handshake_name), 0); ++ blake2s(handshake_psk_name_hash, handshake_psk_name, NULL, NOISE_HASH_LEN, sizeof(handshake_psk_name), 0); ++} ++ ++void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer) ++{ ++ memset(handshake, 0, sizeof(struct noise_handshake)); ++ init_rwsem(&handshake->lock); ++ handshake->entry.type = INDEX_HASHTABLE_HANDSHAKE; ++ handshake->entry.peer = peer; ++ memcpy(handshake->remote_static, peer_public_key, NOISE_PUBLIC_KEY_LEN); ++ handshake->static_identity = static_identity; ++ handshake->state = HANDSHAKE_ZEROED; ++} ++ ++void noise_handshake_clear(struct noise_handshake *handshake) ++{ ++ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ down_write(&handshake->lock); ++ memset(&handshake->ephemeral_public, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->ephemeral_private, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->remote_ephemeral, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->hash, 0, NOISE_HASH_LEN); ++ memset(&handshake->chaining_key, 0, NOISE_HASH_LEN); ++ memset(&handshake->key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ handshake->remote_index = 0; ++ handshake->state = HANDSHAKE_ZEROED; ++ up_write(&handshake->lock); ++ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++} ++ ++static struct noise_keypair *keypair_create(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair = kzalloc(sizeof(struct noise_keypair), GFP_KERNEL); ++ if (unlikely(!keypair)) ++ return NULL; ++ keypair->internal_id = atomic64_inc_return(&keypair_counter); ++ keypair->entry.type = INDEX_HASHTABLE_KEYPAIR; ++ keypair->entry.peer = peer; ++ kref_init(&keypair->refcount); ++ return keypair; ++} ++ ++static void keypair_free_rcu(struct rcu_head *rcu) ++{ ++ struct noise_keypair *keypair = container_of(rcu, struct noise_keypair, rcu); ++ net_dbg_ratelimited("Keypair %Lu destroyed for peer %Lu\n", keypair->internal_id, keypair->entry.peer->internal_id); ++ kzfree(keypair); ++} ++ ++static void keypair_free_kref(struct kref *kref) ++{ ++ struct noise_keypair *keypair = container_of(kref, struct noise_keypair, refcount); ++ index_hashtable_remove(&keypair->entry.peer->device->index_hashtable, &keypair->entry); ++ call_rcu(&keypair->rcu, keypair_free_rcu); ++} ++ ++void noise_keypair_put(struct noise_keypair *keypair) ++{ ++ if (unlikely(!keypair)) ++ return; ++ kref_put(&keypair->refcount, keypair_free_kref); ++} ++ ++struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling noise_keypair_get without holding the RCU read lock."); ++ if (unlikely(!keypair || !kref_get_unless_zero(&keypair->refcount))) ++ return NULL; ++ return keypair; ++} ++ ++void noise_keypairs_clear(struct noise_keypairs *keypairs) ++{ ++ struct noise_keypair *old; ++ mutex_lock(&keypairs->keypair_update_lock); ++ old = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->previous_keypair, NULL); ++ noise_keypair_put(old); ++ old = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ noise_keypair_put(old); ++ old = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->current_keypair, NULL); ++ noise_keypair_put(old); ++ mutex_unlock(&keypairs->keypair_update_lock); ++} ++ ++static void add_new_keypair(struct noise_keypairs *keypairs, struct noise_keypair *new_keypair) ++{ ++ struct noise_keypair *previous_keypair, *next_keypair, *current_keypair; ++ ++ mutex_lock(&keypairs->keypair_update_lock); ++ previous_keypair = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ next_keypair = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ current_keypair = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ if (new_keypair->i_am_the_initiator) { ++ /* If we're the initiator, it means we've sent a handshake, and received ++ * a confirmation response, which means this new keypair can now be used. */ ++ if (next_keypair) { ++ /* If there already was a next keypair pending, we demote it to be ++ * the previous keypair, and free the existing current. ++ * TODO: note that this means KCI can result in this transition. It ++ * would perhaps be more sound to always just get rid of the unused ++ * next keypair instead of putting it in the previous slot, but this ++ * might be a bit less robust. Something to think about and decide on. */ ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ rcu_assign_pointer(keypairs->previous_keypair, next_keypair); ++ noise_keypair_put(current_keypair); ++ } else /* If there wasn't an existing next keypair, we replace the ++ * previous with the current one. */ ++ rcu_assign_pointer(keypairs->previous_keypair, current_keypair); ++ /* At this point we can get rid of the old previous keypair, and set up ++ * the new keypair. */ ++ noise_keypair_put(previous_keypair); ++ rcu_assign_pointer(keypairs->current_keypair, new_keypair); ++ } else { ++ /* If we're the responder, it means we can't use the new keypair until ++ * we receive confirmation via the first data packet, so we get rid of ++ * the existing previous one, the possibly existing next one, and slide ++ * in the new next one. */ ++ rcu_assign_pointer(keypairs->next_keypair, new_keypair); ++ noise_keypair_put(next_keypair); ++ rcu_assign_pointer(keypairs->previous_keypair, NULL); ++ noise_keypair_put(previous_keypair); ++ } ++ mutex_unlock(&keypairs->keypair_update_lock); ++} ++ ++bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair) ++{ ++ bool ret = false; ++ struct noise_keypair *old_keypair; ++ ++ /* TODO: probably this needs the actual mutex, but we're in atomic context, ++ * so we can't take it here. Instead we just rely on RCU for the lookups. */ ++ rcu_read_lock(); ++ if (unlikely(received_keypair == rcu_dereference(keypairs->next_keypair))) { ++ ret = true; ++ /* When we've finally received the confirmation, we slide the next ++ * into the current, the current into the previous, and get rid of ++ * the old previous. */ ++ old_keypair = rcu_dereference(keypairs->previous_keypair); ++ rcu_assign_pointer(keypairs->previous_keypair, rcu_dereference(keypairs->current_keypair)); ++ noise_keypair_put(old_keypair); ++ rcu_assign_pointer(keypairs->current_keypair, received_keypair); ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ } ++ rcu_read_unlock(); ++ ++ return ret; ++} ++ ++void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN]) ++{ ++ down_write(&static_identity->lock); ++ if (private_key) { ++ memcpy(static_identity->static_private, private_key, NOISE_PUBLIC_KEY_LEN); ++ curve25519_generate_public(static_identity->static_public, private_key); ++ static_identity->has_identity = true; ++ } else { ++ memset(static_identity->static_private, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(static_identity->static_public, 0, NOISE_PUBLIC_KEY_LEN); ++ static_identity->has_identity = false; ++ } ++ up_write(&static_identity->lock); ++} ++ ++void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ down_write(&static_identity->lock); ++ if (preshared_key) { ++ memcpy(static_identity->preshared_key, preshared_key, NOISE_SYMMETRIC_KEY_LEN); ++ static_identity->has_psk = true; ++ } else { ++ memset(static_identity->preshared_key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ static_identity->has_psk = false; ++ } ++ up_write(&static_identity->lock); ++} ++ ++/* This is Hugo Krawczyk's HKDF: ++ * - https://eprint.iacr.org/2010/264.pdf ++ * - https://tools.ietf.org/html/rfc5869 ++ */ ++static void kdf(u8 *first_dst, u8 *second_dst, const u8 *data, ++ size_t first_len, size_t second_len, size_t data_len, ++ const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ u8 secret[BLAKE2S_OUTBYTES]; ++ u8 output[BLAKE2S_OUTBYTES + 1]; ++ BUG_ON(first_len > BLAKE2S_OUTBYTES || second_len > BLAKE2S_OUTBYTES); ++ ++ /* Extract entropy from data into secret */ ++ blake2s_hmac(secret, data, chaining_key, BLAKE2S_OUTBYTES, data_len, NOISE_HASH_LEN); ++ ++ /* Expand first key: key = secret, data = 0x1 */ ++ output[0] = 1; ++ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, 1, BLAKE2S_OUTBYTES); ++ memcpy(first_dst, output, first_len); ++ ++ /* Expand second key: key = secret, data = first-key || 0x2 */ ++ output[BLAKE2S_OUTBYTES] = 2; ++ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, BLAKE2S_OUTBYTES + 1, BLAKE2S_OUTBYTES); ++ memcpy(second_dst, output, second_len); ++ ++ /* Clear sensitive data from stack */ ++ memzero_explicit(secret, BLAKE2S_OUTBYTES); ++ memzero_explicit(output, BLAKE2S_OUTBYTES + 1); ++} ++ ++static void symmetric_key_init(struct noise_symmetric_key *key) ++{ ++ spin_lock_init(&key->counter.receive.lock); ++ atomic64_set(&key->counter.counter, 0); ++ memset(key->counter.receive.backtrack, 0, sizeof(key->counter.receive.backtrack)); ++ key->birthdate = get_jiffies_64(); ++ key->is_valid = true; ++} ++ ++static void derive_keys(struct noise_symmetric_key *first_dst, struct noise_symmetric_key *second_dst, const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ kdf(first_dst->key, second_dst->key, NULL, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, chaining_key); ++ symmetric_key_init(first_dst); ++ symmetric_key_init(second_dst); ++} ++ ++static void mix_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], const u8 *src, size_t src_len) ++{ ++ kdf(chaining_key, key, src, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, src_len, chaining_key); ++} ++ ++static void mix_dh(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], ++ const u8 private[NOISE_PUBLIC_KEY_LEN], const u8 public[NOISE_PUBLIC_KEY_LEN]) ++{ ++ u8 dh_calculation[NOISE_PUBLIC_KEY_LEN]; ++ curve25519(dh_calculation, private, public); ++ mix_key(key, chaining_key, dh_calculation, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(dh_calculation, NOISE_PUBLIC_KEY_LEN); ++} ++ ++static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len) ++{ ++ struct blake2s_state blake; ++ blake2s_init(&blake, NOISE_HASH_LEN); ++ blake2s_update(&blake, hash, NOISE_HASH_LEN); ++ blake2s_update(&blake, src, src_len); ++ blake2s_final(&blake, hash, NOISE_HASH_LEN); ++} ++ ++static void handshake_init(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], u8 hash[NOISE_HASH_LEN], ++ const u8 remote_static[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ memset(key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(hash, psk ? handshake_psk_name_hash : handshake_name_hash, NOISE_HASH_LEN); ++ mix_hash(hash, identifier_name, sizeof(identifier_name)); ++ if (psk) { ++ u8 temp_hash[NOISE_HASH_LEN]; ++ kdf(chaining_key, temp_hash, psk, NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, handshake_psk_name_hash); ++ mix_hash(hash, temp_hash, NOISE_HASH_LEN); ++ memzero_explicit(temp_hash, NOISE_HASH_LEN); ++ } else ++ memcpy(chaining_key, handshake_name_hash, NOISE_HASH_LEN); ++ mix_hash(hash, remote_static, NOISE_PUBLIC_KEY_LEN); ++} ++ ++static bool handshake_encrypt(u8 *dst_ciphertext, const u8 *src_plaintext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN]) ++{ ++ if (!chacha20poly1305_encrypt(dst_ciphertext, src_plaintext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key)) ++ return false; ++ mix_hash(hash, dst_ciphertext, noise_encrypted_len(src_len)); ++ return true; ++} ++ ++static bool handshake_decrypt(u8 *dst_plaintext, const u8 *src_ciphertext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN]) ++{ ++ if (!chacha20poly1305_decrypt(dst_plaintext, src_ciphertext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key)) ++ return false; ++ mix_hash(hash, src_ciphertext, src_len); ++ return true; ++} ++ ++static void handshake_nocrypt(u8 *dst, const u8 *src, size_t src_len, u8 hash[NOISE_HASH_LEN]) ++{ ++ memcpy(dst, src, src_len); ++ mix_hash(hash, src, src_len); ++} ++ ++static void tai64n_now(u8 output[NOISE_TIMESTAMP_LEN]) ++{ ++ struct timeval now; ++ do_gettimeofday(&now); ++ /* https://cr.yp.to/libtai/tai64.html */ ++ *(__be64 *)output = cpu_to_be64(4611686018427387914ULL + now.tv_sec); ++ *(__be32 *)(output + sizeof(__be64)) = cpu_to_be32(1000 * now.tv_usec + 500); ++} ++ ++bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake) ++{ ++ u8 timestamp[NOISE_TIMESTAMP_LEN]; ++ bool ret = false; ++ ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (unlikely(!handshake->static_identity->has_identity)) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION); ++ ++ handshake_init(handshake->key, handshake->chaining_key, handshake->hash, handshake->remote_static, ++ handshake->static_identity->has_psk ? handshake->static_identity->preshared_key : NULL); ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private); ++ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash); ++ if (handshake->static_identity->has_psk) ++ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN); ++ ++ /* es */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static); ++ ++ /* s */ ++ if (!handshake_encrypt(dst->encrypted_static, handshake->static_identity->static_public, NOISE_PUBLIC_KEY_LEN, handshake->key, handshake->hash)) ++ goto out; ++ ++ /* ss */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->static_identity->static_private, handshake->remote_static); ++ ++ /* t */ ++ tai64n_now(timestamp); ++ if (!handshake_encrypt(dst->encrypted_timestamp, timestamp, NOISE_TIMESTAMP_LEN, handshake->key, handshake->hash)) ++ goto out; ++ ++ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ ++ ret = true; ++ handshake->state = HANDSHAKE_CREATED_INITIATION; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ return ret; ++} ++ ++struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg) ++{ ++ bool replay_attack, flood_attack; ++ u8 s[NOISE_PUBLIC_KEY_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 t[NOISE_TIMESTAMP_LEN]; ++ struct noise_handshake *handshake; ++ struct wireguard_peer *wg_peer = NULL; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ ++ down_read(&wg->static_identity.lock); ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake_init(key, chaining_key, hash, wg->static_identity.static_public, ++ wg->static_identity.has_psk ? wg->static_identity.preshared_key : NULL); ++ ++ /* e */ ++ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash); ++ if (wg->static_identity.has_psk) ++ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN); ++ ++ /* es */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, e); ++ ++ /* s */ ++ if (!handshake_decrypt(s, src->encrypted_static, sizeof(src->encrypted_static), key, hash)) ++ goto out; ++ ++ /* ss */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, s); ++ ++ /* t */ ++ if (!handshake_decrypt(t, src->encrypted_timestamp, sizeof(src->encrypted_timestamp), key, hash)) ++ goto out; ++ ++ /* Lookup which peer we're actually talking to */ ++ wg_peer = pubkey_hashtable_lookup(&wg->peer_hashtable, s); ++ if (!wg_peer) ++ goto out; ++ handshake = &wg_peer->handshake; ++ down_read(&handshake->lock); ++ replay_attack = memcmp(t, handshake->latest_timestamp, NOISE_TIMESTAMP_LEN) <= 0; ++ flood_attack = !time_is_before_jiffies64(handshake->last_initiation_consumption + INITIATIONS_PER_SECOND); ++ up_read(&handshake->lock); ++ if (replay_attack || flood_attack) { ++ peer_put(wg_peer); ++ wg_peer = NULL; ++ goto out; ++ } ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ memcpy(handshake->latest_timestamp, t, NOISE_TIMESTAMP_LEN); ++ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ handshake->last_initiation_consumption = get_jiffies_64(); ++ handshake->state = HANDSHAKE_CONSUMED_INITIATION; ++ up_write(&handshake->lock); ++ ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ up_read(&wg->static_identity.lock); ++ return wg_peer; ++} ++ ++bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *handshake) ++{ ++ bool ret = false; ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (handshake->state != HANDSHAKE_CONSUMED_INITIATION) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE); ++ dst->receiver_index = handshake->remote_index; ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private); ++ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash); ++ if (handshake->static_identity->has_psk) ++ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN); ++ ++ /* ee */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_ephemeral); ++ ++ /* se */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static); ++ ++ if (!handshake_encrypt(dst->encrypted_nothing, NULL, 0, handshake->key, handshake->hash)) ++ goto out; ++ ++ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ ++ handshake->state = HANDSHAKE_CREATED_RESPONSE; ++ ret = true; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ return ret; ++} ++ ++struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg) ++{ ++ struct noise_handshake *handshake; ++ struct wireguard_peer *ret_peer = NULL; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ enum noise_handshake_state state = HANDSHAKE_ZEROED; ++ ++ down_read(&wg->static_identity.lock); ++ ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake = (struct noise_handshake *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE, src->receiver_index); ++ if (unlikely(!handshake)) ++ goto out; ++ ++ down_read(&handshake->lock); ++ state = handshake->state; ++ memcpy(key, handshake->key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(hash, handshake->hash, NOISE_HASH_LEN); ++ memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN); ++ memcpy(ephemeral_private, handshake->ephemeral_private, NOISE_PUBLIC_KEY_LEN); ++ up_read(&handshake->lock); ++ ++ if (state != HANDSHAKE_CREATED_INITIATION) ++ goto fail; ++ ++ /* e */ ++ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash); ++ if (wg->static_identity.has_psk) ++ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN); ++ ++ /* ee */ ++ mix_dh(key, chaining_key, ephemeral_private, e); ++ ++ /* se */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, e); ++ ++ /* decrypt nothing */ ++ if (!handshake_decrypt(NULL, src->encrypted_nothing, sizeof(src->encrypted_nothing), key, hash)) ++ goto fail; ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ handshake->state = HANDSHAKE_CONSUMED_RESPONSE; ++ up_write(&handshake->lock); ++ ret_peer = handshake->entry.peer; ++ goto out; ++ ++fail: ++ peer_put(handshake->entry.peer); ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN); ++ up_read(&wg->static_identity.lock); ++ return ret_peer; ++} ++ ++bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator) ++{ ++ struct noise_keypair *new_keypair; ++ ++ down_read(&handshake->lock); ++ if (handshake->state != HANDSHAKE_CREATED_RESPONSE && handshake->state != HANDSHAKE_CONSUMED_RESPONSE) ++ goto fail; ++ ++ new_keypair = keypair_create(handshake->entry.peer); ++ if (!new_keypair) ++ goto fail; ++ new_keypair->i_am_the_initiator = i_am_the_initiator; ++ new_keypair->remote_index = handshake->remote_index; ++ ++ if (i_am_the_initiator) ++ derive_keys(&new_keypair->sending, &new_keypair->receiving, handshake->chaining_key); ++ else ++ derive_keys(&new_keypair->receiving, &new_keypair->sending, handshake->chaining_key); ++ up_read(&handshake->lock); ++ ++ add_new_keypair(keypairs, new_keypair); ++ index_hashtable_replace(&handshake->entry.peer->device->index_hashtable, &handshake->entry, &new_keypair->entry); ++ noise_handshake_clear(handshake); ++ net_dbg_ratelimited("Keypair %Lu created for peer %Lu\n", new_keypair->internal_id, new_keypair->entry.peer->internal_id); ++ ++ return true; ++ ++fail: ++ up_read(&handshake->lock); ++ return false; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/peer.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,151 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "peer.h" ++#include "device.h" ++#include "packets.h" ++#include "timers.h" ++#include "hashtables.h" ++#include "noise.h" ++ ++#include ++#include ++#include ++#include ++ ++static atomic64_t peer_counter = ATOMIC64_INIT(0); ++ ++struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN]) ++{ ++ struct wireguard_peer *peer; ++ lockdep_assert_held(&wg->device_update_lock); ++ ++ if (peer_total_count(wg) >= MAX_PEERS_PER_DEVICE) ++ return NULL; ++ ++ peer = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL); ++ if (!peer) ++ return NULL; ++ ++ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) { ++ kfree(peer); ++ return NULL; ++ } ++ ++ peer->internal_id = atomic64_inc_return(&peer_counter); ++ peer->device = wg; ++ cookie_init(&peer->latest_cookie); ++ noise_handshake_init(&peer->handshake, &wg->static_identity, public_key, peer); ++ cookie_checker_precompute_keys(&wg->cookie_checker, peer); ++ mutex_init(&peer->keypairs.keypair_update_lock); ++ INIT_WORK(&peer->transmit_handshake_work, packet_send_queued_handshakes); ++ rwlock_init(&peer->endpoint_lock); ++ skb_queue_head_init(&peer->tx_packet_queue); ++ kref_init(&peer->refcount); ++ pubkey_hashtable_add(&wg->peer_hashtable, peer); ++ list_add_tail(&peer->peer_list, &wg->peer_list); ++ pr_debug("Peer %Lu created\n", peer->internal_id); ++ return peer; ++} ++ ++struct wireguard_peer *peer_get(struct wireguard_peer *peer) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling peer_get without holding the RCU read lock."); ++ if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount))) ++ return NULL; ++ return peer; ++} ++ ++struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer) ++{ ++ rcu_read_lock(); ++ peer = peer_get(peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++/* We have a separate "remove" function to get rid of the final reference because ++ * peer_list, clearing handshakes, and flushing all require mutexes which requires ++ * sleeping, which must only be done from certain contexts. */ ++void peer_remove(struct wireguard_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ lockdep_assert_held(&peer->device->device_update_lock); ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ list_del(&peer->peer_list); ++ timers_uninit_peer(peer); ++ routing_table_remove_by_peer(&peer->device->peer_routing_table, peer); ++ pubkey_hashtable_remove(&peer->device->peer_hashtable, peer); ++ if (peer->device->workqueue) ++ flush_workqueue(peer->device->workqueue); ++ skb_queue_purge(&peer->tx_packet_queue); ++ peer_put(peer); ++} ++ ++static void rcu_release(struct rcu_head *rcu) ++{ ++ struct wireguard_peer *peer = container_of(rcu, struct wireguard_peer, rcu); ++ pr_debug("Peer %Lu (%pISpfsc) destroyed\n", peer->internal_id, &peer->endpoint.addr); ++ skb_queue_purge(&peer->tx_packet_queue); ++ dst_cache_destroy(&peer->endpoint_cache); ++ kzfree(peer); ++} ++ ++static void kref_release(struct kref *refcount) ++{ ++ struct wireguard_peer *peer = container_of(refcount, struct wireguard_peer, refcount); ++ call_rcu(&peer->rcu, rcu_release); ++} ++ ++void peer_put(struct wireguard_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ kref_put(&peer->refcount, kref_release); ++} ++ ++int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data) ++{ ++ struct wireguard_peer *peer, *temp; ++ int ret = 0; ++ ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) { ++ peer = peer_rcu_get(peer); ++ if (unlikely(!peer)) ++ continue; ++ ret = fn(peer, data); ++ peer_put(peer); ++ if (ret < 0) ++ break; ++ } ++ return ret; ++} ++ ++int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data) ++{ ++ int ret; ++ mutex_lock(&wg->device_update_lock); ++ ret = peer_for_each_unlocked(wg, fn, data); ++ mutex_unlock(&wg->device_update_lock); ++ return ret; ++} ++ ++void peer_remove_all(struct wireguard_device *wg) ++{ ++ struct wireguard_peer *peer, *temp; ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) ++ peer_remove(peer); ++} ++ ++unsigned int peer_total_count(struct wireguard_device *wg) ++{ ++ unsigned int i = 0; ++ struct wireguard_peer *peer; ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) ++ ++i; ++ return i; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/ratelimiter.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,138 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "ratelimiter.h" ++#include "peer.h" ++#include "device.h" ++ ++#include ++#include ++#include ++ ++static struct xt_match *v4_match __read_mostly; ++#if IS_ENABLED(CONFIG_IPV6) ++static struct xt_match *v6_match __read_mostly; ++#endif ++ ++enum { ++ RATELIMITER_PACKETS_PER_SECOND = 30, ++ RATELIMITER_PACKETS_BURSTABLE = 5 ++}; ++ ++static inline void cfg_init(struct hashlimit_cfg1 *cfg, int family) ++{ ++ memset(cfg, 0, sizeof(struct hashlimit_cfg1)); ++ if (family == NFPROTO_IPV4) ++ cfg->srcmask = 32; ++ else if (family == NFPROTO_IPV6) ++ cfg->srcmask = 96; ++ cfg->mode = XT_HASHLIMIT_HASH_SIP; /* source IP only -- we could also do source port by ORing this with XT_HASHLIMIT_HASH_SPT */ ++ cfg->avg = XT_HASHLIMIT_SCALE / RATELIMITER_PACKETS_PER_SECOND; /* 30 per second per IP */ ++ cfg->burst = RATELIMITER_PACKETS_BURSTABLE; /* Allow bursts of 5 at a time */ ++ cfg->gc_interval = 1000; /* same as expiration date */ ++ cfg->expire = 1000; /* Units of avg (seconds = 1) times 1000 */ ++ /* cfg->size and cfg->max are computed based on the memory size of left to zero */ ++} ++ ++int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg) ++{ ++ struct net_device *dev = netdev_pub(wg); ++ struct xt_mtchk_param chk = { .net = wg->creating_net }; ++ int ret; ++ ++ memset(ratelimiter, 0, sizeof(struct ratelimiter)); ++ ++ cfg_init(&ratelimiter->v4_info.cfg, NFPROTO_IPV4); ++ memcpy(ratelimiter->v4_info.name, dev->name, IFNAMSIZ); ++ chk.matchinfo = &ratelimiter->v4_info; ++ chk.match = v4_match; ++ chk.family = NFPROTO_IPV4; ++ ret = v4_match->checkentry(&chk); ++ if (ret < 0) ++ return ret; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ cfg_init(&ratelimiter->v6_info.cfg, NFPROTO_IPV6); ++ memcpy(ratelimiter->v6_info.name, dev->name, IFNAMSIZ); ++ chk.matchinfo = &ratelimiter->v6_info; ++ chk.match = v6_match; ++ chk.family = NFPROTO_IPV6; ++ ret = v6_match->checkentry(&chk); ++ if (ret < 0) { ++ struct xt_mtdtor_param dtor_v4 = { ++ .net = wg->creating_net, ++ .match = v4_match, ++ .matchinfo = &ratelimiter->v4_info, ++ .family = NFPROTO_IPV4 ++ }; ++ v4_match->destroy(&dtor_v4); ++ return ret; ++ } ++#endif ++ ++ ratelimiter->net = wg->creating_net; ++ return 0; ++} ++ ++void ratelimiter_uninit(struct ratelimiter *ratelimiter) ++{ ++ struct xt_mtdtor_param dtor = { .net = ratelimiter->net }; ++ ++ dtor.match = v4_match; ++ dtor.matchinfo = &ratelimiter->v4_info; ++ dtor.family = NFPROTO_IPV4; ++ v4_match->destroy(&dtor); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ dtor.match = v6_match; ++ dtor.matchinfo = &ratelimiter->v6_info; ++ dtor.family = NFPROTO_IPV6; ++ v6_match->destroy(&dtor); ++#endif ++} ++ ++bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb) ++{ ++ struct xt_action_param action = { { NULL } }; ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return false; ++ if (ip_hdr(skb)->version == 4) { ++ action.match = v4_match; ++ action.matchinfo = &ratelimiter->v4_info; ++ action.thoff = ip_hdrlen(skb); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (ip_hdr(skb)->version == 6) { ++ action.match = v6_match; ++ action.matchinfo = &ratelimiter->v6_info; ++ } ++#endif ++ else ++ return false; ++ return action.match->match(skb, &action); ++} ++ ++int ratelimiter_module_init(void) ++{ ++ v4_match = xt_request_find_match(NFPROTO_IPV4, "hashlimit", 1); ++ if (IS_ERR(v4_match)) { ++ pr_err("The xt_hashlimit module for IPv4 is required\n"); ++ return PTR_ERR(v4_match); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ v6_match = xt_request_find_match(NFPROTO_IPV6, "hashlimit", 1); ++ if (IS_ERR(v6_match)) { ++ pr_err("The xt_hashlimit module for IPv6 is required\n"); ++ module_put(v4_match->me); ++ return PTR_ERR(v6_match); ++ } ++#endif ++ return 0; ++} ++ ++void ratelimiter_module_deinit(void) ++{ ++ module_put(v4_match->me); ++#if IS_ENABLED(CONFIG_IPV6) ++ module_put(v6_match->me); ++#endif ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/receive.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,311 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "device.h" ++#include "peer.h" ++#include "timers.h" ++#include "messages.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++ ++static inline void rx_stats(struct wireguard_peer *peer, size_t len) ++{ ++ struct pcpu_sw_netstats *tstats = get_cpu_ptr(netdev_pub(peer->device)->tstats); ++ u64_stats_update_begin(&tstats->syncp); ++ tstats->rx_bytes += len; ++ ++tstats->rx_packets; ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); ++ peer->rx_bytes += len; ++} ++ ++static inline void update_latest_addr(struct wireguard_peer *peer, struct sk_buff *skb) ++{ ++ struct endpoint endpoint; ++ if (!socket_endpoint_from_skb(&endpoint, skb)) ++ socket_set_peer_endpoint(peer, &endpoint); ++} ++ ++static inline int skb_data_offset(struct sk_buff *skb, size_t *data_offset, size_t *data_len) ++{ ++ struct udphdr *udp; ++ ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return -EINVAL; ++ if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6)) ++ return -EINVAL; ++ if (unlikely(ip_hdr(skb)->version == 6 && skb->len < sizeof(struct ipv6hdr))) ++ return -EINVAL; ++ ++ udp = udp_hdr(skb); ++ *data_offset = (u8 *)udp - skb->data; ++ if (unlikely(*data_offset > U16_MAX)) { ++ net_dbg_skb_ratelimited("Packet has offset at impossible location from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ if (unlikely(*data_offset + sizeof(struct udphdr) > skb->len)) { ++ net_dbg_skb_ratelimited("Packet isn't big enough to have UDP fields from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ *data_len = ntohs(udp->len); ++ if (unlikely(*data_len < sizeof(struct udphdr))) { ++ net_dbg_skb_ratelimited("UDP packet is reporting too small of a size from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ if (unlikely(*data_len > skb->len - *data_offset)) { ++ net_dbg_skb_ratelimited("UDP packet is lying about its size from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ *data_len -= sizeof(struct udphdr); ++ *data_offset = (u8 *)udp + sizeof(struct udphdr) - skb->data; ++ if (!pskb_may_pull(skb, *data_offset + sizeof(struct message_header))) { ++ net_dbg_skb_ratelimited("Could not pull header into data section from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void receive_handshake_packet(struct wireguard_device *wg, void *data, size_t len, struct sk_buff *skb) ++{ ++ struct wireguard_peer *peer = NULL; ++ enum message_type message_type; ++ bool under_load; ++ enum cookie_mac_state mac_state; ++ bool packet_needs_cookie; ++ ++ message_type = message_determine_type(data, len); ++ ++ if (message_type == MESSAGE_HANDSHAKE_COOKIE) { ++ net_dbg_skb_ratelimited("Receiving cookie response from %pISpfsc\n", skb); ++ cookie_message_consume(data, wg); ++ return; ++ } ++ ++ under_load = skb_queue_len(&wg->incoming_handshakes) >= MAX_QUEUED_INCOMING_HANDSHAKES / 2; ++ mac_state = cookie_validate_packet(&wg->cookie_checker, skb, data, len, under_load); ++ if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) || (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)) ++ packet_needs_cookie = false; ++ else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE) ++ packet_needs_cookie = true; ++ else { ++ net_dbg_skb_ratelimited("Invalid MAC of handshake, dropping packet from %pISpfsc\n", skb); ++ return; ++ } ++ ++ switch (message_type) { ++ case MESSAGE_HANDSHAKE_INITIATION: ++ if (packet_needs_cookie) { ++ struct message_handshake_initiation *message = data; ++ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index); ++ return; ++ } ++ peer = noise_handshake_consume_initiation(data, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("Invalid handshake initiation from %pISpfsc\n", skb); ++ return; ++ } ++ update_latest_addr(peer, skb); ++ net_dbg_ratelimited("Receiving handshake initiation from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ packet_send_handshake_response(peer); ++ break; ++ case MESSAGE_HANDSHAKE_RESPONSE: ++ if (packet_needs_cookie) { ++ struct message_handshake_response *message = data; ++ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index); ++ return; ++ } ++ peer = noise_handshake_consume_response(data, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("Invalid handshake response from %pISpfsc\n", skb); ++ return; ++ } ++ update_latest_addr(peer, skb); ++ net_dbg_ratelimited("Receiving handshake response from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, true)) { ++ timers_ephemeral_key_created(peer); ++ timers_handshake_complete(peer); ++ peer->sent_lastminute_handshake = false; ++ /* Calling this function will either send any existing packets in the queue ++ * and not send a keepalive, which is the best case, Or, if there's nothing ++ * in the queue, it will send a keepalive, in order to give immediate ++ * confirmation of the session. */ ++ packet_send_keepalive(peer); ++ } ++ break; ++ default: ++ WARN(1, "Somehow a wrong type of packet wound up in the handshake queue!\n"); ++ return; ++ } ++ ++ BUG_ON(!peer); ++ ++ rx_stats(peer, len); ++ timers_any_authenticated_packet_received(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ peer_put(peer); ++} ++ ++void packet_process_queued_handshake_packets(struct work_struct *work) ++{ ++ struct wireguard_device *wg = container_of(work, struct wireguard_device, incoming_handshakes_work); ++ struct sk_buff *skb; ++ size_t len, offset; ++ size_t num_processed = 0; ++ ++ while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) { ++ if (!skb_data_offset(skb, &offset, &len)) ++ receive_handshake_packet(wg, skb->data + offset, len, skb); ++ dev_kfree_skb(skb); ++ if (++num_processed == MAX_BURST_INCOMING_HANDSHAKES) { ++ queue_work(wg->workqueue, &wg->incoming_handshakes_work); ++ return; ++ } ++ } ++} ++ ++static void keep_key_fresh(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ if (peer->sent_lastminute_handshake) ++ return; ++ ++ rcu_read_lock(); ++ keypair = rcu_dereference(peer->keypairs.current_keypair); ++ if (likely(keypair && keypair->sending.is_valid) && keypair->i_am_the_initiator && ++ unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT))) ++ send = true; ++ rcu_read_unlock(); ++ ++ if (send) { ++ peer->sent_lastminute_handshake = true; ++ packet_queue_handshake_initiation(peer); ++ } ++} ++ ++struct packet_cb { ++ u8 ds; ++}; ++#define PACKET_CB(skb) ((struct packet_cb *)skb->cb) ++ ++static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer, struct endpoint *endpoint, bool used_new_key, int err) ++{ ++ struct net_device *dev; ++ struct wireguard_peer *routed_peer; ++ struct wireguard_device *wg; ++ ++ if (unlikely(err < 0 || !peer || !endpoint)) { ++ dev_kfree_skb(skb); ++ return; ++ } ++ ++ socket_set_peer_endpoint(peer, endpoint); ++ ++ wg = peer->device; ++ dev = netdev_pub(wg); ++ ++ if (unlikely(used_new_key)) { ++ peer->sent_lastminute_handshake = false; ++ packet_send_queue(peer); ++ } ++ ++ keep_key_fresh(peer); ++ ++ /* A packet with length 0 is a keepalive packet */ ++ if (unlikely(!skb->len)) { ++ net_dbg_ratelimited("Receiving keepalive packet from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ if (!pskb_may_pull(skb, 1 /* For checking the ip version below */)) { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_length_errors; ++ net_dbg_ratelimited("Packet missing IP version from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ skb->dev = dev; ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) { ++ skb->protocol = htons(ETH_P_IP); ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP_ECN_set_ce(ip_hdr(skb)); ++ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) { ++ skb->protocol = htons(ETH_P_IPV6); ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP6_ECN_set_ce(skb, ipv6_hdr(skb)); ++ } else { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_length_errors; ++ net_dbg_ratelimited("Packet neither ipv4 nor ipv6 from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ timers_data_received(peer); ++ ++ routed_peer = routing_table_lookup_src(&wg->peer_routing_table, skb); ++ peer_put(routed_peer); /* We don't need the extra reference. */ ++ ++ if (unlikely(routed_peer != peer)) { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_frame_errors; ++ net_dbg_skb_ratelimited("Packet has unallowed src IP (%pISc) from peer %Lu (%pISpfsc)\n", skb, peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ if (likely(netif_rx(skb) == NET_RX_SUCCESS)) ++ rx_stats(peer, skb->len); ++ else { ++ ++dev->stats.rx_dropped; ++ net_dbg_ratelimited("Failed to give packet to userspace from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ } ++ goto continue_processing; ++ ++packet_processed: ++ dev_kfree_skb(skb); ++continue_processing: ++ timers_any_authenticated_packet_received(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ peer_put(peer); ++} ++ ++void packet_receive(struct wireguard_device *wg, struct sk_buff *skb) ++{ ++ size_t len, offset; ++ ++ if (unlikely(skb_data_offset(skb, &offset, &len) < 0)) ++ goto err; ++ switch (message_determine_type(skb->data + offset, len)) { ++ case MESSAGE_HANDSHAKE_INITIATION: ++ case MESSAGE_HANDSHAKE_RESPONSE: ++ case MESSAGE_HANDSHAKE_COOKIE: ++ if (skb_queue_len(&wg->incoming_handshakes) > MAX_QUEUED_INCOMING_HANDSHAKES) { ++ net_dbg_skb_ratelimited("Too many handshakes queued, dropping packet from %pISpfsc\n", skb); ++ goto err; ++ } ++ if (skb_linearize(skb) < 0) { ++ net_dbg_skb_ratelimited("Unable to linearize handshake skb from %pISpfsc\n", skb); ++ goto err; ++ } ++ skb_queue_tail(&wg->incoming_handshakes, skb); ++ /* Queues up a call to packet_process_queued_handshake_packets(skb): */ ++ queue_work(wg->workqueue, &wg->incoming_handshakes_work); ++ break; ++ case MESSAGE_DATA: ++ PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb); ++ packet_consume_data(skb, offset, wg, receive_data_packet); ++ break; ++ default: ++ net_dbg_skb_ratelimited("Invalid packet from %pISpfsc\n", skb); ++ goto err; ++ } ++ return; ++ ++err: ++ dev_kfree_skb(skb); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/routingtable.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,516 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "routingtable.h" ++#include "peer.h" ++ ++struct routing_table_node { ++ struct routing_table_node __rcu *bit[2]; ++ struct rcu_head rcu; ++ struct wireguard_peer *peer; ++ u8 cidr; ++ u8 bit_at_a, bit_at_b; ++ bool incidental; ++ u8 bits[]; ++}; ++ ++static inline u8 bit_at(const u8 *key, u8 a, u8 b) ++{ ++ return (key[a] >> b) & 1; ++} ++static inline void copy_and_assign_cidr(struct routing_table_node *node, const u8 *src, u8 cidr) ++{ ++ memcpy(node->bits, src, (cidr + 7) / 8); ++ node->bits[(cidr + 7) / 8 - 1] &= 0xff << ((8 - (cidr % 8)) % 8); ++ node->cidr = cidr; ++ node->bit_at_a = cidr / 8; ++ node->bit_at_b = 7 - (cidr % 8); ++} ++ ++/* Non-recursive RCU expansion of: ++ * ++ * free_node(node) ++ * { ++ * if (!node) ++ * return; ++ * free_node(node->bit[0]); ++ * free_node(node->bit[1]); ++ * kfree_rcu(node); ++ * } ++ */ ++#define ref(p) rcu_access_pointer(p) ++#define push(p) do { BUG_ON(len >= 128); stack[len++] = rcu_dereference_protected(p, lockdep_is_held(lock)); } while (0) ++static void free_node(struct routing_table_node *top, struct mutex *lock) ++{ ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node = NULL; ++ struct routing_table_node *prev = NULL; ++ unsigned int len = 0; ++ ++ if (!top) ++ return; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[len - 1]; ++ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) { ++ if (ref(node->bit[0])) ++ push(node->bit[0]); ++ else if (ref(node->bit[1])) ++ push(node->bit[1]); ++ } else if (ref(node->bit[0]) == prev) { ++ if (ref(node->bit[1])) ++ push(node->bit[1]); ++ } else { ++ kfree_rcu(node, rcu); ++ --len; ++ } ++ prev = node; ++ } ++} ++#undef push ++#define push(p) do { BUG_ON(len >= 128); stack[len++] = p; } while (0) ++static bool walk_remove_by_peer(struct routing_table_node __rcu **top, struct wireguard_peer *peer, struct mutex *lock) ++{ ++ struct routing_table_node __rcu **stack[128]; ++ struct routing_table_node __rcu **nptr; ++ struct routing_table_node *node = NULL; ++ struct routing_table_node *prev = NULL; ++ unsigned int len = 0; ++ bool ret = false; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ nptr = stack[len - 1]; ++ node = rcu_dereference_protected(*nptr, lockdep_is_held(lock)); ++ if (!node) { ++ --len; ++ continue; ++ } ++ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) { ++ if (ref(node->bit[0])) ++ push(&node->bit[0]); ++ else if (ref(node->bit[1])) ++ push(&node->bit[1]); ++ } else if (ref(node->bit[0]) == prev) { ++ if (ref(node->bit[1])) ++ push(&node->bit[1]); ++ } else { ++ if (node->peer == peer) { ++ ret = true; ++ node->peer = NULL; ++ node->incidental = true; ++ if (!node->bit[0] || !node->bit[1]) { ++ /* collapse (even if both are null) */ ++ rcu_assign_pointer(*nptr, rcu_dereference_protected(node->bit[!node->bit[0]], lockdep_is_held(lock))); ++ rcu_assign_pointer(node->bit[0], NULL); ++ rcu_assign_pointer(node->bit[1], NULL); ++ free_node(node, lock); ++ } ++ } ++ --len; ++ } ++ prev = node; ++ } ++ ++ return ret; ++} ++#undef ref ++#undef push ++ ++static inline bool match(const struct routing_table_node *node, const u8 *key, u8 match_len) ++{ ++ u8 full_blocks_to_match = match_len / 8; ++ u8 bits_leftover = match_len % 8; ++ u8 mask; ++ const u8 *a = node->bits, *b = key; ++ if (memcmp(a, b, full_blocks_to_match)) ++ return false; ++ if (!bits_leftover) ++ return true; ++ mask = ~(0xff >> bits_leftover); ++ return (a[full_blocks_to_match] & mask) == (b[full_blocks_to_match] & mask); ++} ++ ++static inline u8 common_bits(const struct routing_table_node *node, const u8 *key, u8 match_len) ++{ ++ u8 max = (((match_len > node->cidr) ? match_len : node->cidr) + 7) / 8; ++ u8 bits = 0; ++ u8 i, mask; ++ const u8 *a = node->bits, *b = key; ++ for (i = 0; i < max; ++i, bits += 8) { ++ if (a[i] != b[i]) ++ break; ++ } ++ if (i == max) ++ return bits; ++ for (mask = 128; mask > 0; mask /= 2, ++bits) { ++ if ((a[i] & mask) != (b[i] & mask)) ++ return bits; ++ } ++ BUG(); ++ return bits; ++} ++ ++static int remove(struct routing_table_node __rcu **trie, const u8 *key, u8 cidr, struct mutex *lock) ++{ ++ struct routing_table_node *parent = NULL, *node; ++ node = rcu_dereference_protected(*trie, lockdep_is_held(lock)); ++ while (node && node->cidr <= cidr && match(node, key, node->cidr)) { ++ if (node->cidr == cidr) { ++ /* exact match */ ++ node->incidental = true; ++ node->peer = NULL; ++ if (!node->bit[0] || !node->bit[1]) { ++ /* collapse (even if both are null) */ ++ if (parent) ++ rcu_assign_pointer(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], ++ rcu_dereference_protected(node->bit[(!node->bit[0]) ? 1 : 0], lockdep_is_held(lock))); ++ rcu_assign_pointer(node->bit[0], NULL); ++ rcu_assign_pointer(node->bit[1], NULL); ++ free_node(node, lock); ++ } ++ return 0; ++ } ++ parent = node; ++ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock)); ++ } ++ return -ENOENT; ++} ++ ++static inline struct routing_table_node *find_node(struct routing_table_node *trie, u8 bits, const u8 *key) ++{ ++ struct routing_table_node *node = trie, *found = NULL; ++ while (node && match(node, key, node->cidr)) { ++ if (!node->incidental) ++ found = node; ++ if (node->cidr == bits) ++ break; ++ node = rcu_dereference(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)]); ++ } ++ return found; ++} ++ ++static inline bool node_placement(struct routing_table_node __rcu *trie, const u8 *key, u8 cidr, struct routing_table_node **rnode, struct mutex *lock) ++{ ++ bool exact = false; ++ struct routing_table_node *parent = NULL, *node = rcu_dereference_protected(trie, lockdep_is_held(lock)); ++ while (node && node->cidr <= cidr && match(node, key, node->cidr)) { ++ parent = node; ++ if (parent->cidr == cidr) { ++ exact = true; ++ break; ++ } ++ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock)); ++ } ++ if (rnode) ++ *rnode = parent; ++ return exact; ++} ++ ++static int add(struct routing_table_node __rcu **trie, u8 bits, const u8 *key, u8 cidr, struct wireguard_peer *peer, struct mutex *lock) ++{ ++ struct routing_table_node *node, *parent, *down, *newnode; ++ ++ if (!rcu_access_pointer(*trie)) { ++ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!node) ++ return -ENOMEM; ++ node->peer = peer; ++ copy_and_assign_cidr(node, key, cidr); ++ rcu_assign_pointer(*trie, node); ++ return 0; ++ } ++ if (node_placement(*trie, key, cidr, &node, lock)) { ++ /* exact match */ ++ node->incidental = false; ++ node->peer = peer; ++ return 0; ++ } ++ ++ newnode = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!newnode) ++ return -ENOMEM; ++ newnode->peer = peer; ++ copy_and_assign_cidr(newnode, key, cidr); ++ ++ if (!node) ++ down = rcu_dereference_protected(*trie, lockdep_is_held(lock)); ++ else ++ down = rcu_dereference_protected(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], lockdep_is_held(lock)); ++ if (!down) { ++ rcu_assign_pointer(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], newnode); ++ return 0; ++ } ++ /* here we must be inserting between node and down */ ++ cidr = min(cidr, common_bits(down, key, cidr)); ++ parent = node; ++ ++ /* we either need to make a new branch above down and newnode ++ * or newnode can be the branch. newnode can be the branch if ++ * its cidr == bits_in_common */ ++ if (newnode->cidr == cidr) { ++ /* newnode can be the branch */ ++ rcu_assign_pointer(newnode->bit[bit_at(down->bits, newnode->bit_at_a, newnode->bit_at_b)], down); ++ if (!parent) ++ rcu_assign_pointer(*trie, newnode); ++ else ++ rcu_assign_pointer(parent->bit[bit_at(newnode->bits, parent->bit_at_a, parent->bit_at_b)], newnode); ++ } else { ++ /* reparent */ ++ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!node) { ++ kfree(newnode); ++ return -ENOMEM; ++ } ++ node->incidental = true; ++ copy_and_assign_cidr(node, newnode->bits, cidr); ++ ++ rcu_assign_pointer(node->bit[bit_at(down->bits, node->bit_at_a, node->bit_at_b)], down); ++ rcu_assign_pointer(node->bit[bit_at(newnode->bits, node->bit_at_a, node->bit_at_b)], newnode); ++ if (!parent) ++ rcu_assign_pointer(*trie, node); ++ else ++ rcu_assign_pointer(parent->bit[bit_at(node->bits, parent->bit_at_a, parent->bit_at_b)], node); ++ } ++ return 0; ++} ++ ++#define push(p) do { \ ++ struct routing_table_node *next = (maybe_lock ? rcu_dereference_protected(p, lockdep_is_held(maybe_lock)) : rcu_dereference(p)); \ ++ if (next) { \ ++ BUG_ON(len >= 128); \ ++ stack[len++] = next; \ ++ } \ ++} while (0) ++static int walk_ips(struct routing_table_node *top, int family, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock) ++{ ++ int ret; ++ union nf_inet_addr ip = { .all = { 0 } }; ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node; ++ unsigned int len = 0; ++ struct wireguard_peer *peer; ++ ++ if (!top) ++ return 0; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[--len]; ++ ++ peer = peer_get(node->peer); ++ if (peer) { ++ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4); ++ ret = func(ctx, peer, ip, node->cidr, family); ++ peer_put(peer); ++ if (ret) ++ return ret; ++ } ++ ++ push(node->bit[0]); ++ push(node->bit[1]); ++ } ++ return 0; ++} ++static int walk_ips_by_peer(struct routing_table_node *top, int family, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock) ++{ ++ int ret; ++ union nf_inet_addr ip = { .all = { 0 } }; ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node; ++ unsigned int len = 0; ++ ++ if (!top) ++ return 0; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[--len]; ++ ++ if (node->peer == peer) { ++ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4); ++ ret = func(ctx, ip, node->cidr, family); ++ if (ret) ++ return ret; ++ } ++ ++ push(node->bit[0]); ++ push(node->bit[1]); ++ } ++ return 0; ++} ++#undef push ++ ++void routing_table_init(struct routing_table *table) ++{ ++ memset(table, 0, sizeof(struct routing_table)); ++ mutex_init(&table->table_update_lock); ++} ++ ++void routing_table_free(struct routing_table *table) ++{ ++ mutex_lock(&table->table_update_lock); ++ free_node(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock); ++ rcu_assign_pointer(table->root4, NULL); ++ free_node(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock); ++ rcu_assign_pointer(table->root6, NULL); ++ mutex_unlock(&table->table_update_lock); ++} ++ ++int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer) ++{ ++ int ret; ++ if (cidr > 32) ++ return -EINVAL; ++ mutex_lock(&table->table_update_lock); ++ ret = add(&table->root4, 32, (const u8 *)ip, cidr, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer) ++{ ++ int ret; ++ if (cidr > 128) ++ return -EINVAL; ++ mutex_lock(&table->table_update_lock); ++ ret = add(&table->root6, 128, (const u8 *)ip, cidr, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++/* Returns a strong reference to a peer */ ++inline struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip) ++{ ++ struct wireguard_peer *peer = NULL; ++ struct routing_table_node *node; ++ ++ rcu_read_lock(); ++ node = find_node(rcu_dereference(table->root4), 32, (const u8 *)ip); ++ if (node) ++ peer = peer_get(node->peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++/* Returns a strong reference to a peer */ ++inline struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip) ++{ ++ struct wireguard_peer *peer = NULL; ++ struct routing_table_node *node; ++ ++ rcu_read_lock(); ++ node = find_node(rcu_dereference(table->root6), 128, (const u8 *)ip); ++ if (node) ++ peer = peer_get(node->peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = remove(&table->root4, (const u8 *)ip, cidr, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = remove(&table->root6, (const u8 *)ip, cidr, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer) ++{ ++ bool found; ++ mutex_lock(&table->table_update_lock); ++ found = walk_remove_by_peer(&table->root4, peer, &table->table_update_lock) | walk_remove_by_peer(&table->root6, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return found ? 0 : -EINVAL; ++} ++ ++/* Calls func with a strong reference to each peer, before putting it when the function has completed. ++ * It's thus up to the caller to call peer_put on it if it's going to be used elsewhere after or stored. */ ++int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ rcu_read_lock(); ++ ret = walk_ips(rcu_dereference(table->root4), AF_INET, ctx, func, NULL); ++ rcu_read_unlock(); ++ if (ret) ++ return ret; ++ rcu_read_lock(); ++ ret = walk_ips(rcu_dereference(table->root6), AF_INET6, ctx, func, NULL); ++ rcu_read_unlock(); ++ return ret; ++} ++ ++int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ rcu_read_lock(); ++ ret = walk_ips_by_peer(rcu_dereference(table->root4), AF_INET, ctx, peer, func, NULL); ++ rcu_read_unlock(); ++ if (ret) ++ return ret; ++ rcu_read_lock(); ++ ret = walk_ips_by_peer(rcu_dereference(table->root6), AF_INET6, ctx, peer, func, NULL); ++ rcu_read_unlock(); ++ return ret; ++} ++ ++int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = walk_ips_by_peer(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), AF_INET, ctx, peer, func, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ if (ret) ++ return ret; ++ mutex_lock(&table->table_update_lock); ++ ret = walk_ips_by_peer(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), AF_INET6, ctx, peer, func, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++static inline bool has_valid_ip_header(struct sk_buff *skb) ++{ ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return false; ++ else if (unlikely(skb->len < sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6)) ++ return false; ++ else if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6)) ++ return false; ++ return true; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb) ++{ ++ if (unlikely(!has_valid_ip_header(skb))) ++ return NULL; ++ if (ip_hdr(skb)->version == 4) ++ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->daddr); ++ else if (ip_hdr(skb)->version == 6) ++ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->daddr); ++ return NULL; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb) ++{ ++ if (unlikely(!has_valid_ip_header(skb))) ++ return NULL; ++ if (ip_hdr(skb)->version == 4) ++ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->saddr); ++ else if (ip_hdr(skb)->version == 6) ++ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->saddr); ++ return NULL; ++} ++ ++#include "selftest/routing-table.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/send.c 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,192 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "messages.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void packet_send_handshake_initiation(struct wireguard_peer *peer) ++{ ++ struct message_handshake_initiation packet; ++ ++ down_write(&peer->handshake.lock); ++ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) { ++ up_write(&peer->handshake.lock); ++ return; /* This function is rate limited. */ ++ } ++ peer->last_sent_handshake = get_jiffies_64(); ++ up_write(&peer->handshake.lock); ++ ++ net_dbg_ratelimited("Sending handshake initiation to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ ++ if (noise_handshake_create_initiation(&packet, &peer->handshake)) { ++ cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ timers_any_authenticated_packet_traversal(peer); ++ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_initiation), HANDSHAKE_DSCP); ++ timers_handshake_initiated(peer); ++ } ++} ++ ++void packet_send_queued_handshakes(struct work_struct *work) ++{ ++ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, transmit_handshake_work); ++ packet_send_handshake_initiation(peer); ++ peer_put(peer); ++} ++ ++void packet_queue_handshake_initiation(struct wireguard_peer *peer) ++{ ++ /* First checking the timestamp here is just an optimization; it will ++ * be caught while properly locked inside the actual work queue. */ ++ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) ++ return; ++ ++ peer = peer_rcu_get(peer); ++ if (unlikely(!peer)) ++ return; ++ ++ /* Queues up calling packet_send_queued_handshakes(peer), where we do a peer_put(peer) after: */ ++ if (!queue_work(peer->device->workqueue, &peer->transmit_handshake_work)) ++ peer_put(peer); /* If the work was already queued, we want to drop the extra reference */ ++} ++ ++void packet_send_handshake_response(struct wireguard_peer *peer) ++{ ++ struct message_handshake_response packet; ++ ++ net_dbg_ratelimited("Sending handshake response to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ peer->last_sent_handshake = get_jiffies_64(); ++ ++ if (noise_handshake_create_response(&packet, &peer->handshake)) { ++ cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, false)) { ++ timers_ephemeral_key_created(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_response), HANDSHAKE_DSCP); ++ } ++ } ++} ++ ++void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index) ++{ ++ struct message_handshake_cookie packet; ++ ++ net_dbg_skb_ratelimited("Sending cookie response for denied handshake message for %pISpfsc\n", initiating_skb); ++ cookie_message_create(&packet, initiating_skb, data, data_len, sender_index, &wg->cookie_checker); ++ socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, sizeof(packet)); ++} ++ ++static inline void keep_key_fresh(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ ++ rcu_read_lock(); ++ keypair = rcu_dereference(peer->keypairs.current_keypair); ++ if (likely(keypair && keypair->sending.is_valid) && ++ (unlikely(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES) || ++ (keypair->i_am_the_initiator && unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REKEY_AFTER_TIME))))) ++ send = true; ++ rcu_read_unlock(); ++ ++ if (send) ++ packet_queue_handshake_initiation(peer); ++} ++ ++void packet_send_keepalive(struct wireguard_peer *peer) ++{ ++ struct sk_buff *skb; ++ if (!skb_queue_len(&peer->tx_packet_queue)) { ++ skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return; ++ skb_reserve(skb, DATA_PACKET_HEAD_ROOM); ++ skb->dev = netdev_pub(peer->device); ++ skb_queue_tail(&peer->tx_packet_queue, skb); ++ net_dbg_ratelimited("Sending keepalive packet to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ } ++ packet_send_queue(peer); ++} ++ ++static void message_create_data_done(struct sk_buff_head *queue, struct wireguard_peer *peer) ++{ ++ struct sk_buff *skb, *tmp; ++ bool is_keepalive, data_sent = false; ++ ++ timers_any_authenticated_packet_traversal(peer); ++ skb_queue_walk_safe(queue, skb, tmp) { ++ is_keepalive = skb->len == message_data_len(0); ++ if (likely(!socket_send_skb_to_peer(peer, skb, *(u8 *)skb->cb) && !is_keepalive)) ++ data_sent = true; ++ } ++ if (likely(data_sent)) ++ timers_data_sent(peer); ++ ++ keep_key_fresh(peer); ++ ++ if (unlikely(peer->need_resend_queue)) ++ packet_send_queue(peer); ++} ++ ++void packet_send_queue(struct wireguard_peer *peer) ++{ ++ struct sk_buff_head queue; ++ unsigned long flags; ++ ++ peer->need_resend_queue = false; ++ ++ /* Steal the current queue into our local one. */ ++ skb_queue_head_init(&queue); ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice_init(&peer->tx_packet_queue, &queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ ++ if (unlikely(!skb_queue_len(&queue))) ++ return; ++ ++ /* We submit it for encryption and sending. */ ++ switch (packet_create_data(&queue, peer, message_create_data_done)) { ++ case 0: ++ break; ++ case -EBUSY: ++ /* EBUSY happens when the parallel workers are all filled up, in which ++ * case we should requeue everything. */ ++ ++ /* First, we mark that we should try to do this later, when existing ++ * jobs are done. */ ++ peer->need_resend_queue = true; ++ ++ /* We stick the remaining skbs from local_queue at the top of the peer's ++ * queue again, setting the top of local_queue to be the skb that begins ++ * the requeueing. */ ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice(&queue, &peer->tx_packet_queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ break; ++ case -ENOKEY: ++ /* ENOKEY means that we don't have a valid session for the peer, which ++ * means we should initiate a session, but after requeuing like above. */ ++ ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice(&queue, &peer->tx_packet_queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ ++ packet_queue_handshake_initiation(peer); ++ break; ++ default: ++ /* If we failed for any other reason, we want to just free the packets and ++ * forget about them. We do this unlocked, since we're the only ones with ++ * a reference to the local queue. */ ++ __skb_queue_purge(&queue); ++ } ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/socket.c 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,385 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "packets.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++ struct flowi4 fl = { ++ .saddr = endpoint->src4.s_addr, ++ .daddr = endpoint->addr4.sin_addr.s_addr, ++ .fl4_dport = endpoint->addr4.sin_port, ++ .fl4_sport = htons(wg->incoming_port), ++ .flowi4_mark = wg->fwmark, ++ .flowi4_proto = IPPROTO_UDP ++ }; ++ struct rtable *rt = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb->next = skb->prev = NULL; ++ skb->dev = netdev_pub(wg); ++ ++ rcu_read_lock(); ++ sock = rcu_dereference(wg->sock4); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ if (cache) ++ rt = dst_cache_get_ip4(cache, &fl.saddr); ++ ++ if (!rt) { ++ security_sk_classify_flow(sock, flowi4_to_flowi(&fl)); ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ if (unlikely(IS_ERR(rt) && PTR_ERR(rt) == -EINVAL && fl.saddr)) { ++ endpoint->src4.s_addr = fl.saddr = 0; ++ if (cache) ++ dst_cache_reset(cache); ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ } ++ if (unlikely(IS_ERR(rt))) { ++ ret = PTR_ERR(rt); ++ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(rt->dst.dev == skb->dev)) { ++ dst_release(&rt->dst); ++ ret = -ELOOP; ++ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip4(cache, &rt->dst, fl.saddr); ++ } ++ udp_tunnel_xmit_skb(rt, sock, skb, ++ fl.saddr, fl.daddr, ++ ds, ip4_dst_hoplimit(&rt->dst), 0, ++ fl.fl4_sport, fl.fl4_dport, ++ false, false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static inline int send6(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ struct flowi6 fl = { ++ .saddr = endpoint->src6, ++ .daddr = endpoint->addr6.sin6_addr, ++ .fl6_dport = endpoint->addr6.sin6_port, ++ .fl6_sport = htons(wg->incoming_port), ++ .flowi6_mark = wg->fwmark, ++ .flowi6_oif = endpoint->addr6.sin6_scope_id, ++ .flowi6_proto = IPPROTO_UDP ++ /* TODO: addr->sin6_flowinfo */ ++ }; ++ struct dst_entry *dst = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb->next = skb->prev = NULL; ++ skb->dev = netdev_pub(wg); ++ ++ rcu_read_lock(); ++ sock = rcu_dereference(wg->sock6); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ if (cache) ++ dst = dst_cache_get_ip6(cache, &fl.saddr); ++ ++ if (!dst) { ++ security_sk_classify_flow(sock, flowi6_to_flowi(&fl)); ++ if (unlikely(!ipv6_addr_any(&fl.saddr) && !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) { ++ endpoint->src6 = fl.saddr = in6addr_any; ++ if (cache) ++ dst_cache_reset(cache); ++ } ++ ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); ++ if (unlikely(ret)) { ++ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(dst->dev == skb->dev)) { ++ dst_release(dst); ++ ret = -ELOOP; ++ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip6(cache, dst, &fl.saddr); ++ } ++ ++ udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, ++ &fl.saddr, &fl.daddr, ++ ds, ip6_dst_hoplimit(dst), 0, ++ fl.fl6_sport, fl.fl6_dport, ++ false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock(); ++ return ret; ++#else ++ return -EAFNOSUPPORT; ++#endif ++} ++ ++int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds) ++{ ++ size_t skb_len = skb->len; ++ int ret = -EAFNOSUPPORT; ++ ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ ret = send4(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache); ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ ret = send6(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache); ++ if (likely(!ret)) ++ peer->tx_bytes += skb_len; ++ read_unlock_bh(&peer->endpoint_lock); ++ ++ return ret; ++} ++ ++int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t len, u8 ds) ++{ ++ struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ skb_reserve(skb, SKB_HEADER_LEN); ++ memcpy(skb_put(skb, len), buffer, len); ++ return socket_send_skb_to_peer(peer, skb, ds); ++} ++ ++int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len) ++{ ++ int ret = 0; ++ struct sk_buff *skb; ++ struct endpoint endpoint; ++ ++ if (unlikely(!in_skb)) ++ return -EINVAL; ++ ret = socket_endpoint_from_skb(&endpoint, in_skb); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ skb_reserve(skb, SKB_HEADER_LEN); ++ memcpy(skb_put(skb, len), out_buffer, len); ++ ++ if (endpoint.addr.sa_family == AF_INET) ++ ret = send4(wg, skb, &endpoint, 0, NULL); ++ else if (endpoint.addr.sa_family == AF_INET6) ++ ret = send6(wg, skb, &endpoint, 0, NULL); ++ else ++ ret = -EAFNOSUPPORT; ++ ++ return ret; ++} ++ ++int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb) ++{ ++ memset(endpoint, 0, sizeof(struct endpoint)); ++ if (ip_hdr(skb)->version == 4) { ++ endpoint->addr4.sin_family = AF_INET; ++ endpoint->addr4.sin_port = udp_hdr(skb)->source; ++ endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; ++ endpoint->src4.s_addr = ip_hdr(skb)->daddr; ++ } else if (ip_hdr(skb)->version == 6) { ++ endpoint->addr6.sin6_family = AF_INET6; ++ endpoint->addr6.sin6_port = udp_hdr(skb)->source; ++ endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr; ++ endpoint->addr6.sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, skb->skb_iif); ++ /* TODO: endpoint->addr6.sin6_flowinfo */ ++ endpoint->src6 = ipv6_hdr(skb)->daddr; ++ } else ++ return -EINVAL; ++ return 0; ++} ++ ++void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint) ++{ ++ if (endpoint->addr.sa_family == AF_INET) { ++ read_lock_bh(&peer->endpoint_lock); ++ if (likely(peer->endpoint.addr4.sin_family == AF_INET && ++ peer->endpoint.addr4.sin_port == endpoint->addr4.sin_port && ++ peer->endpoint.addr4.sin_addr.s_addr == endpoint->addr4.sin_addr.s_addr && ++ peer->endpoint.src4.s_addr == endpoint->src4.s_addr)) ++ goto out; ++ read_unlock_bh(&peer->endpoint_lock); ++ write_lock_bh(&peer->endpoint_lock); ++ peer->endpoint.addr4 = endpoint->addr4; ++ peer->endpoint.src4 = endpoint->src4; ++ } else if (endpoint->addr.sa_family == AF_INET6) { ++ read_lock_bh(&peer->endpoint_lock); ++ if (likely(peer->endpoint.addr6.sin6_family == AF_INET6 && ++ peer->endpoint.addr6.sin6_port == endpoint->addr6.sin6_port && ++ /* TODO: peer->endpoint.addr6.sin6_flowinfo == endpoint->addr6.sin6_flowinfo && */ ++ ipv6_addr_equal(&peer->endpoint.addr6.sin6_addr, &endpoint->addr6.sin6_addr) && ++ peer->endpoint.addr6.sin6_scope_id == endpoint->addr6.sin6_scope_id && ++ ipv6_addr_equal(&peer->endpoint.src6, &endpoint->src6))) ++ goto out; ++ read_unlock_bh(&peer->endpoint_lock); ++ write_lock_bh(&peer->endpoint_lock); ++ peer->endpoint.addr6 = endpoint->addr6; ++ peer->endpoint.src6 = endpoint->src6; ++ } else ++ return; ++ dst_cache_reset(&peer->endpoint_cache); ++ write_unlock_bh(&peer->endpoint_lock); ++ return; ++out: ++ read_unlock_bh(&peer->endpoint_lock); ++} ++ ++void socket_clear_peer_endpoint_src(struct wireguard_peer *peer) ++{ ++ write_lock_bh(&peer->endpoint_lock); ++ memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6)); ++ dst_cache_reset(&peer->endpoint_cache); ++ write_unlock_bh(&peer->endpoint_lock); ++} ++ ++static int receive(struct sock *sk, struct sk_buff *skb) ++{ ++ struct wireguard_device *wg; ++ ++ if (unlikely(!sk)) ++ goto err; ++ wg = sk->sk_user_data; ++ if (unlikely(!wg)) ++ goto err; ++ packet_receive(wg, skb); ++ return 0; ++ ++err: ++ kfree_skb(skb); ++ return 0; ++} ++ ++static inline void sock_free(struct sock *sock) ++{ ++ if (unlikely(!sock)) ++ return; ++ sk_clear_memalloc(sock); ++ udp_tunnel_sock_release(sock->sk_socket); ++} ++ ++static inline void set_sock_opts(struct socket *sock) ++{ ++ sock->sk->sk_allocation = GFP_ATOMIC; ++ sock->sk->sk_sndbuf = INT_MAX; ++ sk_set_memalloc(sock->sk); ++} ++ ++int socket_init(struct wireguard_device *wg) ++{ ++ int ret = 0; ++ struct udp_tunnel_sock_cfg cfg = { ++ .sk_user_data = wg, ++ .encap_type = 1, ++ .encap_rcv = receive ++ }; ++ struct socket *new4 = NULL; ++ struct udp_port_cfg port4 = { ++ .family = AF_INET, ++ .local_ip.s_addr = htonl(INADDR_ANY), ++ .local_udp_port = htons(wg->incoming_port), ++ .use_udp_checksums = true ++ }; ++#if IS_ENABLED(CONFIG_IPV6) ++ int retries = 0; ++ struct socket *new6 = NULL; ++ struct udp_port_cfg port6 = { ++ .family = AF_INET6, ++ .local_ip6 = IN6ADDR_ANY_INIT, ++ .local_udp_port = htons(wg->incoming_port), ++ .use_udp6_tx_checksums = true, ++ .use_udp6_rx_checksums = true, ++ .ipv6_v6only = true ++ }; ++retry: ++#endif ++ ++ mutex_lock(&wg->socket_update_lock); ++ ++ if (rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock)) || ++ rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock))) { ++ ret = -EADDRINUSE; ++ goto out; ++ } ++ ++ ret = udp_sock_create(wg->creating_net, &port4, &new4); ++ if (ret < 0) { ++ pr_err("Could not create IPv4 socket\n"); ++ goto out; ++ } ++ wg->incoming_port = ntohs(inet_sk(new4->sk)->inet_sport); ++ ++ set_sock_opts(new4); ++ setup_udp_tunnel_sock(wg->creating_net, new4, &cfg); ++ rcu_assign_pointer(wg->sock4, new4->sk); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (!ipv6_mod_enabled()) ++ goto out; ++ port6.local_udp_port = htons(wg->incoming_port); ++ ret = udp_sock_create(wg->creating_net, &port6, &new6); ++ if (ret < 0) { ++ udp_tunnel_sock_release(new4); ++ rcu_assign_pointer(wg->sock4, NULL); ++ if (ret == -EADDRINUSE && !port4.local_udp_port && retries++ < 100) ++ goto retry; ++ if (!port4.local_udp_port) ++ wg->incoming_port = 0; ++ pr_err("Could not create IPv6 socket\n"); ++ goto out; ++ } ++ set_sock_opts(new6); ++ setup_udp_tunnel_sock(wg->creating_net, new6, &cfg); ++ rcu_assign_pointer(wg->sock6, new6->sk); ++#endif ++ ++out: ++ mutex_unlock(&wg->socket_update_lock); ++ return ret; ++} ++ ++void socket_uninit(struct wireguard_device *wg) ++{ ++ struct sock *old4, *old6; ++ mutex_lock(&wg->socket_update_lock); ++ old4 = rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock)); ++ old6 = rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock)); ++ rcu_assign_pointer(wg->sock4, NULL); ++ rcu_assign_pointer(wg->sock6, NULL); ++ mutex_unlock(&wg->socket_update_lock); ++ synchronize_rcu(); ++ synchronize_net(); ++ sock_free(old4); ++ sock_free(old6); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/timers.c 2017-03-05 17:03:41.529682426 +0200 +@@ -0,0 +1,178 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "packets.h" ++ ++/* ++ * Timer for retransmitting the handshake if we don't hear back after `REKEY_TIMEOUT` ms ++ * Timer for sending empty packet if we have received a packet but after have not sent one for `KEEPALIVE_TIMEOUT` ms ++ * Timer for initiating new handshake if we have sent a packet but after have not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT)` ms ++ * Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms if no new keys have been received ++ * Timer for, if enabled, sending an empty authenticated packet every user-specified seconds ++ */ ++ ++/* This rounds the time down to the closest power of two of the closest quarter second. */ ++static inline unsigned long slack_time(unsigned long time) ++{ ++ return time & ~(roundup_pow_of_two(HZ / 4) - 1); ++} ++ ++#define peer_get_from_ptr(ptr) \ ++ struct wireguard_peer *peer = peer_rcu_get((struct wireguard_peer *)ptr); \ ++ if (unlikely(!peer)) \ ++ return; ++ ++static void expired_retransmit_handshake(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ pr_debug("Handshake for peer %Lu (%pISpfsc) did not complete after %d seconds, retrying\n", peer->internal_id, &peer->endpoint.addr, REKEY_TIMEOUT / HZ); ++ if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) { ++ del_timer(&peer->timer_send_keepalive); ++ /* We remove all existing packets and don't try again, ++ * if we try unsuccessfully for too long to make a handshake. */ ++ skb_queue_purge(&peer->tx_packet_queue); ++ /* We set a timer for destroying any residue that might be left ++ * of a partial exchange. */ ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3)); ++ goto out; ++ } ++ ++ /* We clear the endpoint address src address, in case this is the cause of trouble. */ ++ socket_clear_peer_endpoint_src(peer); ++ ++ packet_queue_handshake_initiation(peer); ++ ++peer->timer_handshake_attempts; ++out: ++ peer_put(peer); ++} ++ ++static void expired_send_keepalive(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ packet_send_keepalive(peer); ++ if (peer->timer_need_another_keepalive) { ++ peer->timer_need_another_keepalive = false; ++ if (peer->timers_enabled) ++ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT); ++ } ++ peer_put(peer); ++} ++ ++static void expired_new_handshake(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ pr_debug("Retrying handshake with peer %Lu (%pISpfsc) because we stopped hearing back after %d seconds\n", peer->internal_id, &peer->endpoint.addr, (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) / HZ); ++ /* We clear the endpoint address src address, in case this is the cause of trouble. */ ++ socket_clear_peer_endpoint_src(peer); ++ packet_queue_handshake_initiation(peer); ++ peer_put(peer); ++} ++ ++static void expired_kill_ephemerals(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ if (!queue_work(peer->device->workqueue, &peer->clear_peer_work)) /* Takes our reference. */ ++ peer_put(peer); /* If the work was already on the queue, we want to drop the extra reference */ ++} ++static void queued_expired_kill_ephemerals(struct work_struct *work) ++{ ++ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, clear_peer_work); ++ pr_debug("Zeroing out all keys for peer %Lu (%pISpfsc), since we haven't received a new one in %d seconds\n", peer->internal_id, &peer->endpoint.addr, (REJECT_AFTER_TIME * 3) / HZ); ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ peer_put(peer); ++} ++ ++static void expired_send_persistent_keepalive(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ if (likely(peer->persistent_keepalive_interval)) ++ packet_send_keepalive(peer); ++ peer_put(peer); ++} ++ ++/* Should be called after an authenticated data packet is sent. */ ++void timers_data_sent(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_send_keepalive); ++ ++ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_new_handshake)) ++ mod_timer(&peer->timer_new_handshake, jiffies + KEEPALIVE_TIMEOUT + REKEY_TIMEOUT); ++} ++ ++/* Should be called after an authenticated data packet is received. */ ++void timers_data_received(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_send_keepalive)) ++ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT); ++ else ++ peer->timer_need_another_keepalive = true; ++} ++ ++/* Should be called after any type of authenticated packet is received -- keepalive or data. */ ++void timers_any_authenticated_packet_received(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_new_handshake); ++} ++ ++/* Should be called after a handshake initiation message is sent. */ ++void timers_handshake_initiated(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_send_keepalive); ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_retransmit_handshake, slack_time(jiffies + REKEY_TIMEOUT + prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX))); ++} ++ ++/* Should be called after a handshake response message is received and processed. */ ++void timers_handshake_complete(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_retransmit_handshake); ++ peer->timer_handshake_attempts = 0; ++} ++ ++/* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */ ++void timers_ephemeral_key_created(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3)); ++ do_gettimeofday(&peer->walltime_last_handshake); ++} ++ ++/* Should be called before an packet with authentication -- data, keepalive, either handshake -- is sent, or after one is received. */ ++void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer) ++{ ++ if (peer->persistent_keepalive_interval && likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_persistent_keepalive, slack_time(jiffies + peer->persistent_keepalive_interval)); ++} ++ ++void timers_init_peer(struct wireguard_peer *peer) ++{ ++ peer->timers_enabled = true; ++ setup_timer(&peer->timer_retransmit_handshake, expired_retransmit_handshake, (unsigned long)peer); ++ setup_timer(&peer->timer_send_keepalive, expired_send_keepalive, (unsigned long)peer); ++ setup_timer(&peer->timer_new_handshake, expired_new_handshake, (unsigned long)peer); ++ setup_timer(&peer->timer_kill_ephemerals, expired_kill_ephemerals, (unsigned long)peer); ++ setup_timer(&peer->timer_persistent_keepalive, expired_send_persistent_keepalive, (unsigned long)peer); ++ INIT_WORK(&peer->clear_peer_work, queued_expired_kill_ephemerals); ++} ++ ++void timers_uninit_peer(struct wireguard_peer *peer) ++{ ++ if (!peer->timers_enabled) ++ return; ++ peer->timers_enabled = false; ++ wmb(); ++ del_timer_sync(&peer->timer_retransmit_handshake); ++ del_timer_sync(&peer->timer_send_keepalive); ++ del_timer_sync(&peer->timer_new_handshake); ++ del_timer_sync(&peer->timer_kill_ephemerals); ++ del_timer_sync(&peer->timer_persistent_keepalive); ++ flush_work(&peer->clear_peer_work); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/config.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,11 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGCONFIG_H ++#define WGCONFIG_H ++ ++struct wireguard_device; ++ ++int config_get_device(struct wireguard_device *wg, void __user *udevice); ++int config_set_device(struct wireguard_device *wg, void __user *udevice); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/cookie.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,51 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGCOOKIE_H ++#define WGCOOKIE_H ++ ++#include "messages.h" ++#include "ratelimiter.h" ++#include ++ ++struct wireguard_peer; ++struct wireguard_device; ++struct sk_buff; ++ ++struct cookie_checker { ++ u8 secret[NOISE_HASH_LEN]; ++ u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ u64 secret_birthdate; ++ struct rw_semaphore secret_lock; ++ struct ratelimiter ratelimiter; ++ struct wireguard_device *device; ++}; ++ ++struct cookie { ++ u64 birthdate; ++ bool is_valid; ++ u8 cookie[COOKIE_LEN]; ++ bool have_sent_mac1; ++ u8 last_mac1_sent[COOKIE_LEN]; ++ u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ struct rw_semaphore lock; ++}; ++ ++enum cookie_mac_state { ++ INVALID_MAC, ++ VALID_MAC_BUT_NO_COOKIE, ++ VALID_MAC_WITH_COOKIE_BUT_RATELIMITED, ++ VALID_MAC_WITH_COOKIE ++}; ++ ++int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg); ++void cookie_checker_uninit(struct cookie_checker *checker); ++void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer); ++void cookie_init(struct cookie *cookie); ++ ++enum cookie_mac_state cookie_validate_packet(struct cookie_checker *checker, struct sk_buff *skb, void *data_start, size_t data_len, bool check_cookie); ++void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer); ++ ++void cookie_message_create(struct message_handshake_cookie *src, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker); ++void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/device.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,45 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGDEVICE_H ++#define WGDEVICE_H ++ ++#include "noise.h" ++#include "routingtable.h" ++#include "hashtables.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct wireguard_device { ++ struct sock __rcu *sock4, *sock6; ++ u16 incoming_port; ++ u32 fwmark; ++ struct net *creating_net; ++ struct workqueue_struct *workqueue; ++ struct workqueue_struct *parallelqueue; ++ struct padata_instance *parallel_send, *parallel_receive; ++ struct noise_static_identity static_identity; ++ struct sk_buff_head incoming_handshakes; ++ struct work_struct incoming_handshakes_work; ++ struct cookie_checker cookie_checker; ++ struct pubkey_hashtable peer_hashtable; ++ struct index_hashtable index_hashtable; ++ struct routing_table peer_routing_table; ++ struct list_head peer_list; ++ struct mutex device_update_lock; ++ struct mutex socket_update_lock; ++#ifdef CONFIG_PM_SLEEP ++ struct notifier_block clear_peers_on_suspend; ++#endif ++}; ++ ++int device_init(void); ++void device_uninit(void); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/hashtables.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,48 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef HASHTABLES_H ++#define HASHTABLES_H ++ ++#include "messages.h" ++ ++#include ++#include ++#include ++ ++struct wireguard_peer; ++ ++struct pubkey_hashtable { ++ DECLARE_HASHTABLE(hashtable, 8); ++ siphash_key_t key; ++ struct mutex lock; ++}; ++ ++void pubkey_hashtable_init(struct pubkey_hashtable *table); ++void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer); ++void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer); ++struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]); ++ ++struct index_hashtable { ++ DECLARE_HASHTABLE(hashtable, 10); ++ siphash_key_t key; ++ spinlock_t lock; ++}; ++ ++enum index_hashtable_type { ++ INDEX_HASHTABLE_HANDSHAKE = (1 << 0), ++ INDEX_HASHTABLE_KEYPAIR = (1 << 1) ++}; ++ ++struct index_hashtable_entry { ++ struct wireguard_peer *peer; ++ struct hlist_node index_hash; ++ enum index_hashtable_type type; ++ __le32 index; ++}; ++void index_hashtable_init(struct index_hashtable *table); ++__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry); ++void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new); ++void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry); ++struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/messages.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * See doc/protocol.md for more info ++ */ ++ ++#ifndef MESSAGES_H ++#define MESSAGES_H ++ ++#include "crypto/curve25519.h" ++#include "crypto/chacha20poly1305.h" ++#include "crypto/blake2s.h" ++ ++#include ++#include ++ ++enum noise_lengths { ++ NOISE_PUBLIC_KEY_LEN = CURVE25519_POINT_SIZE, ++ NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEYLEN, ++ NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32), ++ NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAGLEN, ++ NOISE_HASH_LEN = BLAKE2S_OUTBYTES ++}; ++ ++#define noise_encrypted_len(plain_len) (plain_len + NOISE_AUTHTAG_LEN) ++ ++enum cookie_values { ++ COOKIE_SECRET_MAX_AGE = 2 * 60 * HZ, ++ COOKIE_SECRET_LATENCY = 5 * HZ, ++ COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCELEN, ++ COOKIE_LEN = 16 ++}; ++ ++enum counter_values { ++ COUNTER_BITS_TOTAL = 2048, ++ COUNTER_REDUNDANT_BITS = BITS_PER_LONG, ++ COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS ++}; ++ ++enum limits { ++ REKEY_AFTER_MESSAGES = U64_MAX - 0xffff, ++ REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1, ++ REKEY_TIMEOUT = 5 * HZ, ++ REKEY_TIMEOUT_JITTER_MAX = HZ / 3, ++ REKEY_AFTER_TIME = 120 * HZ, ++ REJECT_AFTER_TIME = 180 * HZ, ++ INITIATIONS_PER_SECOND = HZ / 50, ++ MAX_PEERS_PER_DEVICE = U16_MAX, ++ KEEPALIVE_TIMEOUT = 10 * HZ, ++ MAX_TIMER_HANDSHAKES = (90 * HZ) / REKEY_TIMEOUT, ++ MAX_QUEUED_INCOMING_HANDSHAKES = 4096, ++ MAX_BURST_INCOMING_HANDSHAKES = 16, ++ MAX_QUEUED_OUTGOING_PACKETS = 1024 ++}; ++ ++enum message_type { ++ MESSAGE_INVALID = 0, ++ MESSAGE_HANDSHAKE_INITIATION = 1, ++ MESSAGE_HANDSHAKE_RESPONSE = 2, ++ MESSAGE_HANDSHAKE_COOKIE = 3, ++ MESSAGE_DATA = 4, ++ MESSAGE_TOTAL = 5 ++}; ++ ++struct message_header { ++ /* The actual layout of this that we want is: ++ * u8 type ++ * u8 reserved_zero[3] ++ * ++ * But it turns out that by encoding this as little endian, ++ * we achieve the same thing, and it makes checking faster. ++ */ ++ __le32 type; ++}; ++ ++struct message_macs { ++ u8 mac1[COOKIE_LEN]; ++ u8 mac2[COOKIE_LEN]; ++}; ++ ++struct message_handshake_initiation { ++ struct message_header header; ++ __le32 sender_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)]; ++ u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_response { ++ struct message_header header; ++ __le32 sender_index; ++ __le32 receiver_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_nothing[noise_encrypted_len(0)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_cookie { ++ struct message_header header; ++ __le32 receiver_index; ++ u8 nonce[COOKIE_NONCE_LEN]; ++ u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)]; ++}; ++ ++struct message_data { ++ struct message_header header; ++ __le32 key_idx; ++ __le64 counter; ++ u8 encrypted_data[]; ++}; ++ ++#define message_data_len(plain_len) (noise_encrypted_len(plain_len) + sizeof(struct message_data)) ++ ++enum message_alignments { ++ MESSAGE_PADDING_MULTIPLE = 16, ++ MESSAGE_MINIMUM_LENGTH = message_data_len(0) ++}; ++ ++#define SKB_HEADER_LEN (max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + sizeof(struct udphdr) + NET_SKB_PAD) ++#define DATA_PACKET_HEAD_ROOM ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4) ++ ++enum { ++ HANDSHAKE_DSCP = 0b10001000 /* AF41, plus 00 ECN */ ++}; ++ ++static inline enum message_type message_determine_type(void *src, size_t src_len) ++{ ++ struct message_header *header = src; ++ if (unlikely(src_len < sizeof(struct message_header))) ++ return MESSAGE_INVALID; ++ if (header->type == cpu_to_le32(MESSAGE_DATA) && src_len >= MESSAGE_MINIMUM_LENGTH) ++ return MESSAGE_DATA; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) && src_len == sizeof(struct message_handshake_initiation)) ++ return MESSAGE_HANDSHAKE_INITIATION; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) && src_len == sizeof(struct message_handshake_response)) ++ return MESSAGE_HANDSHAKE_RESPONSE; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) && src_len == sizeof(struct message_handshake_cookie)) ++ return MESSAGE_HANDSHAKE_COOKIE; ++ return MESSAGE_INVALID; ++} ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/noise.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * See doc/protocol.md and https://github.com/trevp/noise/blob/master/noise.md for more info ++ */ ++ ++#ifndef NOISE_H ++#define NOISE_H ++ ++#include "messages.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++union noise_counter { ++ struct { ++ u64 counter; ++ unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; ++ spinlock_t lock; ++ } receive; ++ atomic64_t counter; ++}; ++ ++struct noise_symmetric_key { ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ union noise_counter counter; ++ u64 birthdate; ++ bool is_valid; ++}; ++ ++struct noise_keypair { ++ struct index_hashtable_entry entry; ++ struct noise_symmetric_key sending; ++ struct noise_symmetric_key receiving; ++ __le32 remote_index; ++ bool i_am_the_initiator; ++ struct kref refcount; ++ struct rcu_head rcu; ++ u64 internal_id; ++}; ++ ++struct noise_keypairs { ++ struct noise_keypair __rcu *current_keypair; ++ struct noise_keypair __rcu *previous_keypair; ++ struct noise_keypair __rcu *next_keypair; ++ struct mutex keypair_update_lock; ++}; ++ ++struct noise_static_identity { ++ bool has_identity, has_psk; ++ u8 static_public[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]; ++ struct rw_semaphore lock; ++}; ++ ++enum noise_handshake_state { ++ HANDSHAKE_ZEROED, ++ HANDSHAKE_CREATED_INITIATION, ++ HANDSHAKE_CONSUMED_INITIATION, ++ HANDSHAKE_CREATED_RESPONSE, ++ HANDSHAKE_CONSUMED_RESPONSE ++}; ++ ++struct noise_handshake { ++ struct index_hashtable_entry entry; ++ ++ enum noise_handshake_state state; ++ u64 last_initiation_consumption; ++ ++ struct noise_static_identity *static_identity; ++ ++ u8 ephemeral_public[NOISE_PUBLIC_KEY_LEN]; ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ ++ u8 remote_static[NOISE_PUBLIC_KEY_LEN]; ++ u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ ++ u8 latest_timestamp[NOISE_TIMESTAMP_LEN]; ++ __le32 remote_index; ++ ++ /* Protects all members except the immutable (after noise_peer_init): remote_static, static_identity */ ++ struct rw_semaphore lock; ++}; ++ ++struct wireguard_peer; ++struct wireguard_device; ++struct message_header; ++struct message_handshake_initiation; ++struct message_handshake_response; ++struct message_data; ++struct message_handshake_cookie; ++ ++void noise_init(void); ++void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer); ++void noise_handshake_clear(struct noise_handshake *handshake); ++void noise_keypair_put(struct noise_keypair *keypair); ++struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair); ++void noise_keypairs_clear(struct noise_keypairs *keypairs); ++bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair); ++ ++void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN]); ++void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]); ++ ++bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake); ++struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg); ++ ++bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *peer); ++struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg); ++ ++bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/packets.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,44 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef PACKETS_H ++#define PACKETS_H ++ ++#include "noise.h" ++#include "messages.h" ++#include "socket.h" ++ ++#include ++#include ++ ++struct wireguard_device; ++struct wireguard_peer; ++struct sk_buff; ++ ++/* receive.c */ ++void packet_receive(struct wireguard_device *wg, struct sk_buff *skb); ++void packet_process_queued_handshake_packets(struct work_struct *work); ++ ++/* send.c */ ++void packet_send_queue(struct wireguard_peer *peer); ++void packet_send_keepalive(struct wireguard_peer *peer); ++void packet_queue_handshake_initiation(struct wireguard_peer *peer); ++void packet_send_queued_handshakes(struct work_struct *work); ++void packet_send_handshake_response(struct wireguard_peer *peer); ++void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index); ++ ++/* data.c */ ++typedef void (*packet_create_data_callback_t)(struct sk_buff_head *, struct wireguard_peer *); ++typedef void (*packet_consume_data_callback_t)(struct sk_buff *skb, struct wireguard_peer *, struct endpoint *, bool used_new_key, int err); ++int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback); ++void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback); ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++int packet_init_data_caches(void); ++void packet_deinit_data_caches(void); ++#endif ++ ++#ifdef DEBUG ++bool packet_counter_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/peer.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,75 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef PEER_H ++#define PEER_H ++ ++#include "noise.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct wireguard_device; ++ ++struct endpoint { ++ union { ++ struct sockaddr addr; ++ struct sockaddr_in addr4; ++ struct sockaddr_in6 addr6; ++ }; ++ union { ++ struct in_addr src4; ++ struct in6_addr src6; ++ }; ++}; ++ ++struct wireguard_peer { ++ struct wireguard_device *device; ++ struct endpoint endpoint; ++ struct dst_cache endpoint_cache; ++ rwlock_t endpoint_lock; ++ struct noise_handshake handshake; ++ struct noise_keypairs keypairs; ++ u64 last_sent_handshake; ++ struct work_struct transmit_handshake_work, clear_peer_work; ++ struct cookie latest_cookie; ++ struct hlist_node pubkey_hash; ++ u64 rx_bytes, tx_bytes; ++ struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive; ++ unsigned int timer_handshake_attempts; ++ unsigned long persistent_keepalive_interval; ++ bool timers_enabled; ++ bool timer_need_another_keepalive; ++ bool need_resend_queue; ++ bool sent_lastminute_handshake; ++ struct timeval walltime_last_handshake; ++ struct sk_buff_head tx_packet_queue; ++ struct kref refcount; ++ struct rcu_head rcu; ++ struct list_head peer_list; ++ u64 internal_id; ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ atomic_t parallel_encryption_inflight; ++#endif ++}; ++ ++struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN]); ++ ++struct wireguard_peer *peer_get(struct wireguard_peer *peer); ++struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer); ++ ++void peer_put(struct wireguard_peer *peer); ++void peer_remove(struct wireguard_peer *peer); ++void peer_remove_all(struct wireguard_device *wg); ++ ++struct wireguard_peer *peer_lookup_by_index(struct wireguard_device *wg, u32 index); ++ ++int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data); ++int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data); ++ ++unsigned int peer_total_count(struct wireguard_device *wg); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/ratelimiter.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,26 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef RATELIMITER_H ++#define RATELIMITER_H ++ ++#include ++ ++struct wireguard_device; ++struct sk_buff; ++ ++struct ratelimiter { ++ struct net *net; ++ struct xt_hashlimit_mtinfo1 v4_info; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct xt_hashlimit_mtinfo1 v6_info; ++#endif ++}; ++ ++int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg); ++void ratelimiter_uninit(struct ratelimiter *ratelimiter); ++bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb); ++ ++int ratelimiter_module_init(void); ++void ratelimiter_module_deinit(void); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/routingtable.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,40 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef ROUTINGTABLE_H ++#define ROUTINGTABLE_H ++ ++#include ++#include ++#include ++ ++struct wireguard_peer; ++struct routing_table_node; ++ ++struct routing_table { ++ struct routing_table_node __rcu *root4; ++ struct routing_table_node __rcu *root6; ++ struct mutex table_update_lock; ++}; ++ ++void routing_table_init(struct routing_table *table); ++void routing_table_free(struct routing_table *table); ++int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer); ++int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer); ++int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr); ++int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr); ++int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer); ++int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family)); ++int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)); ++int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)); ++ ++/* These return a strong reference to a peer: */ ++struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip); ++struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip); ++struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb); ++struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb); ++ ++#ifdef DEBUG ++bool routing_table_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/socket.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,24 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGSOCKET_H ++#define WGSOCKET_H ++ ++#include ++#include ++#include ++#include ++ ++struct wireguard_device; ++struct endpoint; ++ ++int socket_init(struct wireguard_device *wg); ++void socket_uninit(struct wireguard_device *wg); ++int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data, size_t len, u8 ds); ++int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds); ++int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len); ++ ++int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb); ++void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint); ++void socket_clear_peer_endpoint_src(struct wireguard_peer *peer); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/timers.h 2017-03-05 17:03:41.529682426 +0200 +@@ -0,0 +1,19 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGTIMERS_H ++#define WGTIMERS_H ++ ++struct wireguard_peer; ++ ++void timers_init_peer(struct wireguard_peer *peer); ++void timers_uninit_peer(struct wireguard_peer *peer); ++ ++void timers_data_sent(struct wireguard_peer *peer); ++void timers_data_received(struct wireguard_peer *peer); ++void timers_any_authenticated_packet_received(struct wireguard_peer *peer); ++void timers_handshake_initiated(struct wireguard_peer *peer); ++void timers_handshake_complete(struct wireguard_peer *peer); ++void timers_ephemeral_key_created(struct wireguard_peer *peer); ++void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/uapi.h 2017-03-05 17:03:41.530682431 +0200 +@@ -0,0 +1,159 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * Userspace API for WireGuard ++ * --------------------------- ++ * ++ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: NULL }): ++ * ++ * Returns the number of bytes required to hold the peers of a device (`ret_peers_size`). ++ * ++ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }): ++ * ++ * Retrevies device info, peer info, and ipmask info. ++ * ++ * `user_pointer` must point to a region of memory of size `sizeof(struct wgdevice) + ret_peers_size` ++ * and containing the structure `struct wgdevice { .peers_size: ret_peers_size }`. ++ * ++ * Writes to `user_pointer` a succession of structs: ++ * ++ * struct wgdevice { .num_peers = 3 } ++ * struct wgpeer { .num_ipmasks = 4 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 2 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 0 } ++ * ++ * Returns 0 on success. Returns -EMSGSIZE if there is too much data for the size of passed-in ++ * memory, in which case, this should be recalculated using the call above. Returns -errno if ++ * another error occured. ++ * ++ * ioctl(WG_SET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }): ++ * ++ * Sets device info, peer info, and ipmask info. ++ * ++ * `user_pointer` must point to a region of memory containing a succession of structs: ++ * ++ * struct wgdevice { .num_peers = 3 } ++ * struct wgpeer { .num_ipmasks = 4 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 2 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 0 } ++ * ++ * If `wgdevice->flags & WGDEVICE_REPLACE_PEERS` is true, removes all peers of device before adding new ones. ++ * If `wgpeer->flags & WGPEER_REMOVE_ME` is true, the peer identified by `wgpeer->public_key` is removed. ++ * If `wgpeer->flags & WGPEER_REPLACE_IPMASKS` is true, removes all ipmasks before adding new ones. ++ * If `wgdevice->private_key` is filled with zeros, no action is taken on the private key. ++ * If `wgdevice->preshared_key` is filled with zeros, no action is taken on the pre-shared key. ++ * If `wgdevice->flags & WGDEVICE_REMOVE_PRIVATE_KEY` is true, the private key is removed. ++ * If `wgdevice->flags & WGDEVICE_REMOVE_PRESHARED_KEY` is true, the pre-shared key is removed. ++ * ++ * Returns 0 on success, or -errno if an error occurred. ++ */ ++ ++ ++#ifndef WGUAPI_H ++#define WGUAPI_H ++ ++#ifdef __linux__ ++#include ++#else ++#include ++typedef uint8_t __u8; ++typedef uint16_t __u16; ++typedef uint32_t __u32; ++typedef uint64_t __u64; ++typedef int32_t __s32; ++#endif ++#ifdef __KERNEL__ ++#include ++#include ++#else ++#include ++#include ++#include ++#include ++#endif ++ ++#define WG_GET_DEVICE (SIOCDEVPRIVATE + 0) ++#define WG_SET_DEVICE (SIOCDEVPRIVATE + 1) ++ ++#define WG_KEY_LEN 32 ++ ++struct wgipmask { ++ __s32 family; ++ union { ++ struct in_addr ip4; ++ struct in6_addr ip6; ++ }; ++ __u8 cidr; ++}; ++ ++enum { ++ WGPEER_REMOVE_ME = (1 << 0), ++ WGPEER_REPLACE_IPMASKS = (1 << 1) ++}; ++struct wgpeer { ++ __u8 public_key[WG_KEY_LEN]; /* Get/Set */ ++ __u32 flags; /* Set */ ++ ++ union { ++ struct sockaddr addr; ++ struct sockaddr_in addr4; ++ struct sockaddr_in6 addr6; ++ } endpoint; /* Get/Set */ ++ ++ struct timeval last_handshake_time; /* Get */ ++ __u64 rx_bytes, tx_bytes; /* Get */ ++ __u16 persistent_keepalive_interval; /* Get/Set -- 0 = off, 0xffff = unset */ ++ ++ __u16 num_ipmasks; /* Get/Set */ ++}; ++ ++enum { ++ WGDEVICE_REPLACE_PEERS = (1 << 0), ++ WGDEVICE_REMOVE_PRIVATE_KEY = (1 << 1), ++ WGDEVICE_REMOVE_PRESHARED_KEY = (1 << 2), ++ WGDEVICE_REMOVE_FWMARK = (1 << 3) ++}; ++struct wgdevice { ++ char interface[IFNAMSIZ]; /* Get */ ++ __u32 flags; /* Set */ ++ ++ __u8 public_key[WG_KEY_LEN]; /* Get */ ++ __u8 private_key[WG_KEY_LEN]; /* Get/Set */ ++ __u8 preshared_key[WG_KEY_LEN]; /* Get/Set */ ++ __u32 fwmark; /* Get/Set */ ++ __u16 port; /* Get/Set */ ++ ++ union { ++ __u16 num_peers; /* Get/Set */ ++ __u32 peers_size; /* Get */ ++ }; ++}; ++ ++/* These are simply for convenience in iterating. It allows you to write something like: ++ * ++ * for_each_wgpeer(device, peer, i) { ++ * for_each_wgipmask(peer, ipmask, j) { ++ * do_something_with_ipmask(ipmask); ++ * } ++ * } ++ */ ++#define for_each_wgpeer(__dev, __peer, __i) for ((__i) = 0, (__peer) = (struct wgpeer *)((uint8_t *)(__dev) + sizeof(struct wgdevice)); \ ++ (__i) < (__dev)->num_peers; \ ++ ++(__i), (__peer) = (struct wgpeer *)((uint8_t *)(__peer) + sizeof(struct wgpeer) + (sizeof(struct wgipmask) * (__peer)->num_ipmasks))) ++ ++#define for_each_wgipmask(__peer, __ipmask, __i) for ((__i) = 0, (__ipmask) = (struct wgipmask *)((uint8_t *)(__peer) + sizeof(struct wgpeer)); \ ++ (__i) < (__peer)->num_ipmasks; \ ++ ++(__i), (__ipmask) = (struct wgipmask *)((uint8_t *)(__ipmask) + sizeof(struct wgipmask))) ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/version.h 2017-03-05 17:03:41.530682431 +0200 +@@ -0,0 +1 @@ ++#define WIREGUARD_VERSION "0.0.20170223" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/blake2s.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,556 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++static const u8 blake2s_testvecs[][BLAKE2S_OUTBYTES] = { ++ { 0x69, 0x21, 0x7A, 0x30, 0x79, 0x90, 0x80, 0x94, 0xE1, 0x11, 0x21, 0xD0, 0x42, 0x35, 0x4A, 0x7C, 0x1F, 0x55, 0xB6, 0x48, 0x2C, 0xA1, 0xA5, 0x1E, 0x1B, 0x25, 0x0D, 0xFD, 0x1E, 0xD0, 0xEE, 0xF9 }, ++ { 0xE3, 0x4D, 0x74, 0xDB, 0xAF, 0x4F, 0xF4, 0xC6, 0xAB, 0xD8, 0x71, 0xCC, 0x22, 0x04, 0x51, 0xD2, 0xEA, 0x26, 0x48, 0x84, 0x6C, 0x77, 0x57, 0xFB, 0xAA, 0xC8, 0x2F, 0xE5, 0x1A, 0xD6, 0x4B, 0xEA }, ++ { 0xDD, 0xAD, 0x9A, 0xB1, 0x5D, 0xAC, 0x45, 0x49, 0xBA, 0x42, 0xF4, 0x9D, 0x26, 0x24, 0x96, 0xBE, 0xF6, 0xC0, 0xBA, 0xE1, 0xDD, 0x34, 0x2A, 0x88, 0x08, 0xF8, 0xEA, 0x26, 0x7C, 0x6E, 0x21, 0x0C }, ++ { 0xE8, 0xF9, 0x1C, 0x6E, 0xF2, 0x32, 0xA0, 0x41, 0x45, 0x2A, 0xB0, 0xE1, 0x49, 0x07, 0x0C, 0xDD, 0x7D, 0xD1, 0x76, 0x9E, 0x75, 0xB3, 0xA5, 0x92, 0x1B, 0xE3, 0x78, 0x76, 0xC4, 0x5C, 0x99, 0x00 }, ++ { 0x0C, 0xC7, 0x0E, 0x00, 0x34, 0x8B, 0x86, 0xBA, 0x29, 0x44, 0xD0, 0xC3, 0x20, 0x38, 0xB2, 0x5C, 0x55, 0x58, 0x4F, 0x90, 0xDF, 0x23, 0x04, 0xF5, 0x5F, 0xA3, 0x32, 0xAF, 0x5F, 0xB0, 0x1E, 0x20 }, ++ { 0xEC, 0x19, 0x64, 0x19, 0x10, 0x87, 0xA4, 0xFE, 0x9D, 0xF1, 0xC7, 0x95, 0x34, 0x2A, 0x02, 0xFF, 0xC1, 0x91, 0xA5, 0xB2, 0x51, 0x76, 0x48, 0x56, 0xAE, 0x5B, 0x8B, 0x57, 0x69, 0xF0, 0xC6, 0xCD }, ++ { 0xE1, 0xFA, 0x51, 0x61, 0x8D, 0x7D, 0xF4, 0xEB, 0x70, 0xCF, 0x0D, 0x5A, 0x9E, 0x90, 0x6F, 0x80, 0x6E, 0x9D, 0x19, 0xF7, 0xF4, 0xF0, 0x1E, 0x3B, 0x62, 0x12, 0x88, 0xE4, 0x12, 0x04, 0x05, 0xD6 }, ++ { 0x59, 0x80, 0x01, 0xFA, 0xFB, 0xE8, 0xF9, 0x4E, 0xC6, 0x6D, 0xC8, 0x27, 0xD0, 0x12, 0xCF, 0xCB, 0xBA, 0x22, 0x28, 0x56, 0x9F, 0x44, 0x8E, 0x89, 0xEA, 0x22, 0x08, 0xC8, 0xBF, 0x76, 0x92, 0x93 }, ++ { 0xC7, 0xE8, 0x87, 0xB5, 0x46, 0x62, 0x36, 0x35, 0xE9, 0x3E, 0x04, 0x95, 0x59, 0x8F, 0x17, 0x26, 0x82, 0x19, 0x96, 0xC2, 0x37, 0x77, 0x05, 0xB9, 0x3A, 0x1F, 0x63, 0x6F, 0x87, 0x2B, 0xFA, 0x2D }, ++ { 0xC3, 0x15, 0xA4, 0x37, 0xDD, 0x28, 0x06, 0x2A, 0x77, 0x0D, 0x48, 0x19, 0x67, 0x13, 0x6B, 0x1B, 0x5E, 0xB8, 0x8B, 0x21, 0xEE, 0x53, 0xD0, 0x32, 0x9C, 0x58, 0x97, 0x12, 0x6E, 0x9D, 0xB0, 0x2C }, ++ { 0xBB, 0x47, 0x3D, 0xED, 0xDC, 0x05, 0x5F, 0xEA, 0x62, 0x28, 0xF2, 0x07, 0xDA, 0x57, 0x53, 0x47, 0xBB, 0x00, 0x40, 0x4C, 0xD3, 0x49, 0xD3, 0x8C, 0x18, 0x02, 0x63, 0x07, 0xA2, 0x24, 0xCB, 0xFF }, ++ { 0x68, 0x7E, 0x18, 0x73, 0xA8, 0x27, 0x75, 0x91, 0xBB, 0x33, 0xD9, 0xAD, 0xF9, 0xA1, 0x39, 0x12, 0xEF, 0xEF, 0xE5, 0x57, 0xCA, 0xFC, 0x39, 0xA7, 0x95, 0x26, 0x23, 0xE4, 0x72, 0x55, 0xF1, 0x6D }, ++ { 0x1A, 0xC7, 0xBA, 0x75, 0x4D, 0x6E, 0x2F, 0x94, 0xE0, 0xE8, 0x6C, 0x46, 0xBF, 0xB2, 0x62, 0xAB, 0xBB, 0x74, 0xF4, 0x50, 0xEF, 0x45, 0x6D, 0x6B, 0x4D, 0x97, 0xAA, 0x80, 0xCE, 0x6D, 0xA7, 0x67 }, ++ { 0x01, 0x2C, 0x97, 0x80, 0x96, 0x14, 0x81, 0x6B, 0x5D, 0x94, 0x94, 0x47, 0x7D, 0x4B, 0x68, 0x7D, 0x15, 0xB9, 0x6E, 0xB6, 0x9C, 0x0E, 0x80, 0x74, 0xA8, 0x51, 0x6F, 0x31, 0x22, 0x4B, 0x5C, 0x98 }, ++ { 0x91, 0xFF, 0xD2, 0x6C, 0xFA, 0x4D, 0xA5, 0x13, 0x4C, 0x7E, 0xA2, 0x62, 0xF7, 0x88, 0x9C, 0x32, 0x9F, 0x61, 0xF6, 0xA6, 0x57, 0x22, 0x5C, 0xC2, 0x12, 0xF4, 0x00, 0x56, 0xD9, 0x86, 0xB3, 0xF4 }, ++ { 0xD9, 0x7C, 0x82, 0x8D, 0x81, 0x82, 0xA7, 0x21, 0x80, 0xA0, 0x6A, 0x78, 0x26, 0x83, 0x30, 0x67, 0x3F, 0x7C, 0x4E, 0x06, 0x35, 0x94, 0x7C, 0x04, 0xC0, 0x23, 0x23, 0xFD, 0x45, 0xC0, 0xA5, 0x2D }, ++ { 0xEF, 0xC0, 0x4C, 0xDC, 0x39, 0x1C, 0x7E, 0x91, 0x19, 0xBD, 0x38, 0x66, 0x8A, 0x53, 0x4E, 0x65, 0xFE, 0x31, 0x03, 0x6D, 0x6A, 0x62, 0x11, 0x2E, 0x44, 0xEB, 0xEB, 0x11, 0xF9, 0xC5, 0x70, 0x80 }, ++ { 0x99, 0x2C, 0xF5, 0xC0, 0x53, 0x44, 0x2A, 0x5F, 0xBC, 0x4F, 0xAF, 0x58, 0x3E, 0x04, 0xE5, 0x0B, 0xB7, 0x0D, 0x2F, 0x39, 0xFB, 0xB6, 0xA5, 0x03, 0xF8, 0x9E, 0x56, 0xA6, 0x3E, 0x18, 0x57, 0x8A }, ++ { 0x38, 0x64, 0x0E, 0x9F, 0x21, 0x98, 0x3E, 0x67, 0xB5, 0x39, 0xCA, 0xCC, 0xAE, 0x5E, 0xCF, 0x61, 0x5A, 0xE2, 0x76, 0x4F, 0x75, 0xA0, 0x9C, 0x9C, 0x59, 0xB7, 0x64, 0x83, 0xC1, 0xFB, 0xC7, 0x35 }, ++ { 0x21, 0x3D, 0xD3, 0x4C, 0x7E, 0xFE, 0x4F, 0xB2, 0x7A, 0x6B, 0x35, 0xF6, 0xB4, 0x00, 0x0D, 0x1F, 0xE0, 0x32, 0x81, 0xAF, 0x3C, 0x72, 0x3E, 0x5C, 0x9F, 0x94, 0x74, 0x7A, 0x5F, 0x31, 0xCD, 0x3B }, ++ { 0xEC, 0x24, 0x6E, 0xEE, 0xB9, 0xCE, 0xD3, 0xF7, 0xAD, 0x33, 0xED, 0x28, 0x66, 0x0D, 0xD9, 0xBB, 0x07, 0x32, 0x51, 0x3D, 0xB4, 0xE2, 0xFA, 0x27, 0x8B, 0x60, 0xCD, 0xE3, 0x68, 0x2A, 0x4C, 0xCD }, ++ { 0xAC, 0x9B, 0x61, 0xD4, 0x46, 0x64, 0x8C, 0x30, 0x05, 0xD7, 0x89, 0x2B, 0xF3, 0xA8, 0x71, 0x9F, 0x4C, 0x81, 0x81, 0xCF, 0xDC, 0xBC, 0x2B, 0x79, 0xFE, 0xF1, 0x0A, 0x27, 0x9B, 0x91, 0x10, 0x95 }, ++ { 0x7B, 0xF8, 0xB2, 0x29, 0x59, 0xE3, 0x4E, 0x3A, 0x43, 0xF7, 0x07, 0x92, 0x23, 0xE8, 0x3A, 0x97, 0x54, 0x61, 0x7D, 0x39, 0x1E, 0x21, 0x3D, 0xFD, 0x80, 0x8E, 0x41, 0xB9, 0xBE, 0xAD, 0x4C, 0xE7 }, ++ { 0x68, 0xD4, 0xB5, 0xD4, 0xFA, 0x0E, 0x30, 0x2B, 0x64, 0xCC, 0xC5, 0xAF, 0x79, 0x29, 0x13, 0xAC, 0x4C, 0x88, 0xEC, 0x95, 0xC0, 0x7D, 0xDF, 0x40, 0x69, 0x42, 0x56, 0xEB, 0x88, 0xCE, 0x9F, 0x3D }, ++ { 0xB2, 0xC2, 0x42, 0x0F, 0x05, 0xF9, 0xAB, 0xE3, 0x63, 0x15, 0x91, 0x93, 0x36, 0xB3, 0x7E, 0x4E, 0x0F, 0xA3, 0x3F, 0xF7, 0xE7, 0x6A, 0x49, 0x27, 0x67, 0x00, 0x6F, 0xDB, 0x5D, 0x93, 0x54, 0x62 }, ++ { 0x13, 0x4F, 0x61, 0xBB, 0xD0, 0xBB, 0xB6, 0x9A, 0xED, 0x53, 0x43, 0x90, 0x45, 0x51, 0xA3, 0xE6, 0xC1, 0xAA, 0x7D, 0xCD, 0xD7, 0x7E, 0x90, 0x3E, 0x70, 0x23, 0xEB, 0x7C, 0x60, 0x32, 0x0A, 0xA7 }, ++ { 0x46, 0x93, 0xF9, 0xBF, 0xF7, 0xD4, 0xF3, 0x98, 0x6A, 0x7D, 0x17, 0x6E, 0x6E, 0x06, 0xF7, 0x2A, 0xD1, 0x49, 0x0D, 0x80, 0x5C, 0x99, 0xE2, 0x53, 0x47, 0xB8, 0xDE, 0x77, 0xB4, 0xDB, 0x6D, 0x9B }, ++ { 0x85, 0x3E, 0x26, 0xF7, 0x41, 0x95, 0x3B, 0x0F, 0xD5, 0xBD, 0xB4, 0x24, 0xE8, 0xAB, 0x9E, 0x8B, 0x37, 0x50, 0xEA, 0xA8, 0xEF, 0x61, 0xE4, 0x79, 0x02, 0xC9, 0x1E, 0x55, 0x4E, 0x9C, 0x73, 0xB9 }, ++ { 0xF7, 0xDE, 0x53, 0x63, 0x61, 0xAB, 0xAA, 0x0E, 0x15, 0x81, 0x56, 0xCF, 0x0E, 0xA4, 0xF6, 0x3A, 0x99, 0xB5, 0xE4, 0x05, 0x4F, 0x8F, 0xA4, 0xC9, 0xD4, 0x5F, 0x62, 0x85, 0xCA, 0xD5, 0x56, 0x94 }, ++ { 0x4C, 0x23, 0x06, 0x08, 0x86, 0x0A, 0x99, 0xAE, 0x8D, 0x7B, 0xD5, 0xC2, 0xCC, 0x17, 0xFA, 0x52, 0x09, 0x6B, 0x9A, 0x61, 0xBE, 0xDB, 0x17, 0xCB, 0x76, 0x17, 0x86, 0x4A, 0xD2, 0x9C, 0xA7, 0xA6 }, ++ { 0xAE, 0xB9, 0x20, 0xEA, 0x87, 0x95, 0x2D, 0xAD, 0xB1, 0xFB, 0x75, 0x92, 0x91, 0xE3, 0x38, 0x81, 0x39, 0xA8, 0x72, 0x86, 0x50, 0x01, 0x88, 0x6E, 0xD8, 0x47, 0x52, 0xE9, 0x3C, 0x25, 0x0C, 0x2A }, ++ { 0xAB, 0xA4, 0xAD, 0x9B, 0x48, 0x0B, 0x9D, 0xF3, 0xD0, 0x8C, 0xA5, 0xE8, 0x7B, 0x0C, 0x24, 0x40, 0xD4, 0xE4, 0xEA, 0x21, 0x22, 0x4C, 0x2E, 0xB4, 0x2C, 0xBA, 0xE4, 0x69, 0xD0, 0x89, 0xB9, 0x31 }, ++ { 0x05, 0x82, 0x56, 0x07, 0xD7, 0xFD, 0xF2, 0xD8, 0x2E, 0xF4, 0xC3, 0xC8, 0xC2, 0xAE, 0xA9, 0x61, 0xAD, 0x98, 0xD6, 0x0E, 0xDF, 0xF7, 0xD0, 0x18, 0x98, 0x3E, 0x21, 0x20, 0x4C, 0x0D, 0x93, 0xD1 }, ++ { 0xA7, 0x42, 0xF8, 0xB6, 0xAF, 0x82, 0xD8, 0xA6, 0xCA, 0x23, 0x57, 0xC5, 0xF1, 0xCF, 0x91, 0xDE, 0xFB, 0xD0, 0x66, 0x26, 0x7D, 0x75, 0xC0, 0x48, 0xB3, 0x52, 0x36, 0x65, 0x85, 0x02, 0x59, 0x62 }, ++ { 0x2B, 0xCA, 0xC8, 0x95, 0x99, 0x00, 0x0B, 0x42, 0xC9, 0x5A, 0xE2, 0x38, 0x35, 0xA7, 0x13, 0x70, 0x4E, 0xD7, 0x97, 0x89, 0xC8, 0x4F, 0xEF, 0x14, 0x9A, 0x87, 0x4F, 0xF7, 0x33, 0xF0, 0x17, 0xA2 }, ++ { 0xAC, 0x1E, 0xD0, 0x7D, 0x04, 0x8F, 0x10, 0x5A, 0x9E, 0x5B, 0x7A, 0xB8, 0x5B, 0x09, 0xA4, 0x92, 0xD5, 0xBA, 0xFF, 0x14, 0xB8, 0xBF, 0xB0, 0xE9, 0xFD, 0x78, 0x94, 0x86, 0xEE, 0xA2, 0xB9, 0x74 }, ++ { 0xE4, 0x8D, 0x0E, 0xCF, 0xAF, 0x49, 0x7D, 0x5B, 0x27, 0xC2, 0x5D, 0x99, 0xE1, 0x56, 0xCB, 0x05, 0x79, 0xD4, 0x40, 0xD6, 0xE3, 0x1F, 0xB6, 0x24, 0x73, 0x69, 0x6D, 0xBF, 0x95, 0xE0, 0x10, 0xE4 }, ++ { 0x12, 0xA9, 0x1F, 0xAD, 0xF8, 0xB2, 0x16, 0x44, 0xFD, 0x0F, 0x93, 0x4F, 0x3C, 0x4A, 0x8F, 0x62, 0xBA, 0x86, 0x2F, 0xFD, 0x20, 0xE8, 0xE9, 0x61, 0x15, 0x4C, 0x15, 0xC1, 0x38, 0x84, 0xED, 0x3D }, ++ { 0x7C, 0xBE, 0xE9, 0x6E, 0x13, 0x98, 0x97, 0xDC, 0x98, 0xFB, 0xEF, 0x3B, 0xE8, 0x1A, 0xD4, 0xD9, 0x64, 0xD2, 0x35, 0xCB, 0x12, 0x14, 0x1F, 0xB6, 0x67, 0x27, 0xE6, 0xE5, 0xDF, 0x73, 0xA8, 0x78 }, ++ { 0xEB, 0xF6, 0x6A, 0xBB, 0x59, 0x7A, 0xE5, 0x72, 0xA7, 0x29, 0x7C, 0xB0, 0x87, 0x1E, 0x35, 0x5A, 0xCC, 0xAF, 0xAD, 0x83, 0x77, 0xB8, 0xE7, 0x8B, 0xF1, 0x64, 0xCE, 0x2A, 0x18, 0xDE, 0x4B, 0xAF }, ++ { 0x71, 0xB9, 0x33, 0xB0, 0x7E, 0x4F, 0xF7, 0x81, 0x8C, 0xE0, 0x59, 0xD0, 0x08, 0x82, 0x9E, 0x45, 0x3C, 0x6F, 0xF0, 0x2E, 0xC0, 0xA7, 0xDB, 0x39, 0x3F, 0xC2, 0xD8, 0x70, 0xF3, 0x7A, 0x72, 0x86 }, ++ { 0x7C, 0xF7, 0xC5, 0x13, 0x31, 0x22, 0x0B, 0x8D, 0x3E, 0xBA, 0xED, 0x9C, 0x29, 0x39, 0x8A, 0x16, 0xD9, 0x81, 0x56, 0xE2, 0x61, 0x3C, 0xB0, 0x88, 0xF2, 0xB0, 0xE0, 0x8A, 0x1B, 0xE4, 0xCF, 0x4F }, ++ { 0x3E, 0x41, 0xA1, 0x08, 0xE0, 0xF6, 0x4A, 0xD2, 0x76, 0xB9, 0x79, 0xE1, 0xCE, 0x06, 0x82, 0x79, 0xE1, 0x6F, 0x7B, 0xC7, 0xE4, 0xAA, 0x1D, 0x21, 0x1E, 0x17, 0xB8, 0x11, 0x61, 0xDF, 0x16, 0x02 }, ++ { 0x88, 0x65, 0x02, 0xA8, 0x2A, 0xB4, 0x7B, 0xA8, 0xD8, 0x67, 0x10, 0xAA, 0x9D, 0xE3, 0xD4, 0x6E, 0xA6, 0x5C, 0x47, 0xAF, 0x6E, 0xE8, 0xDE, 0x45, 0x0C, 0xCE, 0xB8, 0xB1, 0x1B, 0x04, 0x5F, 0x50 }, ++ { 0xC0, 0x21, 0xBC, 0x5F, 0x09, 0x54, 0xFE, 0xE9, 0x4F, 0x46, 0xEA, 0x09, 0x48, 0x7E, 0x10, 0xA8, 0x48, 0x40, 0xD0, 0x2F, 0x64, 0x81, 0x0B, 0xC0, 0x8D, 0x9E, 0x55, 0x1F, 0x7D, 0x41, 0x68, 0x14 }, ++ { 0x20, 0x30, 0x51, 0x6E, 0x8A, 0x5F, 0xE1, 0x9A, 0xE7, 0x9C, 0x33, 0x6F, 0xCE, 0x26, 0x38, 0x2A, 0x74, 0x9D, 0x3F, 0xD0, 0xEC, 0x91, 0xE5, 0x37, 0xD4, 0xBD, 0x23, 0x58, 0xC1, 0x2D, 0xFB, 0x22 }, ++ { 0x55, 0x66, 0x98, 0xDA, 0xC8, 0x31, 0x7F, 0xD3, 0x6D, 0xFB, 0xDF, 0x25, 0xA7, 0x9C, 0xB1, 0x12, 0xD5, 0x42, 0x58, 0x60, 0x60, 0x5C, 0xBA, 0xF5, 0x07, 0xF2, 0x3B, 0xF7, 0xE9, 0xF4, 0x2A, 0xFE }, ++ { 0x2F, 0x86, 0x7B, 0xA6, 0x77, 0x73, 0xFD, 0xC3, 0xE9, 0x2F, 0xCE, 0xD9, 0x9A, 0x64, 0x09, 0xAD, 0x39, 0xD0, 0xB8, 0x80, 0xFD, 0xE8, 0xF1, 0x09, 0xA8, 0x17, 0x30, 0xC4, 0x45, 0x1D, 0x01, 0x78 }, ++ { 0x17, 0x2E, 0xC2, 0x18, 0xF1, 0x19, 0xDF, 0xAE, 0x98, 0x89, 0x6D, 0xFF, 0x29, 0xDD, 0x98, 0x76, 0xC9, 0x4A, 0xF8, 0x74, 0x17, 0xF9, 0xAE, 0x4C, 0x70, 0x14, 0xBB, 0x4E, 0x4B, 0x96, 0xAF, 0xC7 }, ++ { 0x3F, 0x85, 0x81, 0x4A, 0x18, 0x19, 0x5F, 0x87, 0x9A, 0xA9, 0x62, 0xF9, 0x5D, 0x26, 0xBD, 0x82, 0xA2, 0x78, 0xF2, 0xB8, 0x23, 0x20, 0x21, 0x8F, 0x6B, 0x3B, 0xD6, 0xF7, 0xF6, 0x67, 0xA6, 0xD9 }, ++ { 0x1B, 0x61, 0x8F, 0xBA, 0xA5, 0x66, 0xB3, 0xD4, 0x98, 0xC1, 0x2E, 0x98, 0x2C, 0x9E, 0xC5, 0x2E, 0x4D, 0xA8, 0x5A, 0x8C, 0x54, 0xF3, 0x8F, 0x34, 0xC0, 0x90, 0x39, 0x4F, 0x23, 0xC1, 0x84, 0xC1 }, ++ { 0x0C, 0x75, 0x8F, 0xB5, 0x69, 0x2F, 0xFD, 0x41, 0xA3, 0x57, 0x5D, 0x0A, 0xF0, 0x0C, 0xC7, 0xFB, 0xF2, 0xCB, 0xE5, 0x90, 0x5A, 0x58, 0x32, 0x3A, 0x88, 0xAE, 0x42, 0x44, 0xF6, 0xE4, 0xC9, 0x93 }, ++ { 0xA9, 0x31, 0x36, 0x0C, 0xAD, 0x62, 0x8C, 0x7F, 0x12, 0xA6, 0xC1, 0xC4, 0xB7, 0x53, 0xB0, 0xF4, 0x06, 0x2A, 0xEF, 0x3C, 0xE6, 0x5A, 0x1A, 0xE3, 0xF1, 0x93, 0x69, 0xDA, 0xDF, 0x3A, 0xE2, 0x3D }, ++ { 0xCB, 0xAC, 0x7D, 0x77, 0x3B, 0x1E, 0x3B, 0x3C, 0x66, 0x91, 0xD7, 0xAB, 0xB7, 0xE9, 0xDF, 0x04, 0x5C, 0x8B, 0xA1, 0x92, 0x68, 0xDE, 0xD1, 0x53, 0x20, 0x7F, 0x5E, 0x80, 0x43, 0x52, 0xEC, 0x5D }, ++ { 0x23, 0xA1, 0x96, 0xD3, 0x80, 0x2E, 0xD3, 0xC1, 0xB3, 0x84, 0x01, 0x9A, 0x82, 0x32, 0x58, 0x40, 0xD3, 0x2F, 0x71, 0x95, 0x0C, 0x45, 0x80, 0xB0, 0x34, 0x45, 0xE0, 0x89, 0x8E, 0x14, 0x05, 0x3C }, ++ { 0xF4, 0x49, 0x54, 0x70, 0xF2, 0x26, 0xC8, 0xC2, 0x14, 0xBE, 0x08, 0xFD, 0xFA, 0xD4, 0xBC, 0x4A, 0x2A, 0x9D, 0xBE, 0xA9, 0x13, 0x6A, 0x21, 0x0D, 0xF0, 0xD4, 0xB6, 0x49, 0x29, 0xE6, 0xFC, 0x14 }, ++ { 0xE2, 0x90, 0xDD, 0x27, 0x0B, 0x46, 0x7F, 0x34, 0xAB, 0x1C, 0x00, 0x2D, 0x34, 0x0F, 0xA0, 0x16, 0x25, 0x7F, 0xF1, 0x9E, 0x58, 0x33, 0xFD, 0xBB, 0xF2, 0xCB, 0x40, 0x1C, 0x3B, 0x28, 0x17, 0xDE }, ++ { 0x9F, 0xC7, 0xB5, 0xDE, 0xD3, 0xC1, 0x50, 0x42, 0xB2, 0xA6, 0x58, 0x2D, 0xC3, 0x9B, 0xE0, 0x16, 0xD2, 0x4A, 0x68, 0x2D, 0x5E, 0x61, 0xAD, 0x1E, 0xFF, 0x9C, 0x63, 0x30, 0x98, 0x48, 0xF7, 0x06 }, ++ { 0x8C, 0xCA, 0x67, 0xA3, 0x6D, 0x17, 0xD5, 0xE6, 0x34, 0x1C, 0xB5, 0x92, 0xFD, 0x7B, 0xEF, 0x99, 0x26, 0xC9, 0xE3, 0xAA, 0x10, 0x27, 0xEA, 0x11, 0xA7, 0xD8, 0xBD, 0x26, 0x0B, 0x57, 0x6E, 0x04 }, ++ { 0x40, 0x93, 0x92, 0xF5, 0x60, 0xF8, 0x68, 0x31, 0xDA, 0x43, 0x73, 0xEE, 0x5E, 0x00, 0x74, 0x26, 0x05, 0x95, 0xD7, 0xBC, 0x24, 0x18, 0x3B, 0x60, 0xED, 0x70, 0x0D, 0x45, 0x83, 0xD3, 0xF6, 0xF0 }, ++ { 0x28, 0x02, 0x16, 0x5D, 0xE0, 0x90, 0x91, 0x55, 0x46, 0xF3, 0x39, 0x8C, 0xD8, 0x49, 0x16, 0x4A, 0x19, 0xF9, 0x2A, 0xDB, 0xC3, 0x61, 0xAD, 0xC9, 0x9B, 0x0F, 0x20, 0xC8, 0xEA, 0x07, 0x10, 0x54 }, ++ { 0xAD, 0x83, 0x91, 0x68, 0xD9, 0xF8, 0xA4, 0xBE, 0x95, 0xBA, 0x9E, 0xF9, 0xA6, 0x92, 0xF0, 0x72, 0x56, 0xAE, 0x43, 0xFE, 0x6F, 0x98, 0x64, 0xE2, 0x90, 0x69, 0x1B, 0x02, 0x56, 0xCE, 0x50, 0xA9 }, ++ { 0x75, 0xFD, 0xAA, 0x50, 0x38, 0xC2, 0x84, 0xB8, 0x6D, 0x6E, 0x8A, 0xFF, 0xE8, 0xB2, 0x80, 0x7E, 0x46, 0x7B, 0x86, 0x60, 0x0E, 0x79, 0xAF, 0x36, 0x89, 0xFB, 0xC0, 0x63, 0x28, 0xCB, 0xF8, 0x94 }, ++ { 0xE5, 0x7C, 0xB7, 0x94, 0x87, 0xDD, 0x57, 0x90, 0x24, 0x32, 0xB2, 0x50, 0x73, 0x38, 0x13, 0xBD, 0x96, 0xA8, 0x4E, 0xFC, 0xE5, 0x9F, 0x65, 0x0F, 0xAC, 0x26, 0xE6, 0x69, 0x6A, 0xEF, 0xAF, 0xC3 }, ++ { 0x56, 0xF3, 0x4E, 0x8B, 0x96, 0x55, 0x7E, 0x90, 0xC1, 0xF2, 0x4B, 0x52, 0xD0, 0xC8, 0x9D, 0x51, 0x08, 0x6A, 0xCF, 0x1B, 0x00, 0xF6, 0x34, 0xCF, 0x1D, 0xDE, 0x92, 0x33, 0xB8, 0xEA, 0xAA, 0x3E }, ++ { 0x1B, 0x53, 0xEE, 0x94, 0xAA, 0xF3, 0x4E, 0x4B, 0x15, 0x9D, 0x48, 0xDE, 0x35, 0x2C, 0x7F, 0x06, 0x61, 0xD0, 0xA4, 0x0E, 0xDF, 0xF9, 0x5A, 0x0B, 0x16, 0x39, 0xB4, 0x09, 0x0E, 0x97, 0x44, 0x72 }, ++ { 0x05, 0x70, 0x5E, 0x2A, 0x81, 0x75, 0x7C, 0x14, 0xBD, 0x38, 0x3E, 0xA9, 0x8D, 0xDA, 0x54, 0x4E, 0xB1, 0x0E, 0x6B, 0xC0, 0x7B, 0xAE, 0x43, 0x5E, 0x25, 0x18, 0xDB, 0xE1, 0x33, 0x52, 0x53, 0x75 }, ++ { 0xD8, 0xB2, 0x86, 0x6E, 0x8A, 0x30, 0x9D, 0xB5, 0x3E, 0x52, 0x9E, 0xC3, 0x29, 0x11, 0xD8, 0x2F, 0x5C, 0xA1, 0x6C, 0xFF, 0x76, 0x21, 0x68, 0x91, 0xA9, 0x67, 0x6A, 0xA3, 0x1A, 0xAA, 0x6C, 0x42 }, ++ { 0xF5, 0x04, 0x1C, 0x24, 0x12, 0x70, 0xEB, 0x04, 0xC7, 0x1E, 0xC2, 0xC9, 0x5D, 0x4C, 0x38, 0xD8, 0x03, 0xB1, 0x23, 0x7B, 0x0F, 0x29, 0xFD, 0x4D, 0xB3, 0xEB, 0x39, 0x76, 0x69, 0xE8, 0x86, 0x99 }, ++ { 0x9A, 0x4C, 0xE0, 0x77, 0xC3, 0x49, 0x32, 0x2F, 0x59, 0x5E, 0x0E, 0xE7, 0x9E, 0xD0, 0xDA, 0x5F, 0xAB, 0x66, 0x75, 0x2C, 0xBF, 0xEF, 0x8F, 0x87, 0xD0, 0xE9, 0xD0, 0x72, 0x3C, 0x75, 0x30, 0xDD }, ++ { 0x65, 0x7B, 0x09, 0xF3, 0xD0, 0xF5, 0x2B, 0x5B, 0x8F, 0x2F, 0x97, 0x16, 0x3A, 0x0E, 0xDF, 0x0C, 0x04, 0xF0, 0x75, 0x40, 0x8A, 0x07, 0xBB, 0xEB, 0x3A, 0x41, 0x01, 0xA8, 0x91, 0x99, 0x0D, 0x62 }, ++ { 0x1E, 0x3F, 0x7B, 0xD5, 0xA5, 0x8F, 0xA5, 0x33, 0x34, 0x4A, 0xA8, 0xED, 0x3A, 0xC1, 0x22, 0xBB, 0x9E, 0x70, 0xD4, 0xEF, 0x50, 0xD0, 0x04, 0x53, 0x08, 0x21, 0x94, 0x8F, 0x5F, 0xE6, 0x31, 0x5A }, ++ { 0x80, 0xDC, 0xCF, 0x3F, 0xD8, 0x3D, 0xFD, 0x0D, 0x35, 0xAA, 0x28, 0x58, 0x59, 0x22, 0xAB, 0x89, 0xD5, 0x31, 0x39, 0x97, 0x67, 0x3E, 0xAF, 0x90, 0x5C, 0xEA, 0x9C, 0x0B, 0x22, 0x5C, 0x7B, 0x5F }, ++ { 0x8A, 0x0D, 0x0F, 0xBF, 0x63, 0x77, 0xD8, 0x3B, 0xB0, 0x8B, 0x51, 0x4B, 0x4B, 0x1C, 0x43, 0xAC, 0xC9, 0x5D, 0x75, 0x17, 0x14, 0xF8, 0x92, 0x56, 0x45, 0xCB, 0x6B, 0xC8, 0x56, 0xCA, 0x15, 0x0A }, ++ { 0x9F, 0xA5, 0xB4, 0x87, 0x73, 0x8A, 0xD2, 0x84, 0x4C, 0xC6, 0x34, 0x8A, 0x90, 0x19, 0x18, 0xF6, 0x59, 0xA3, 0xB8, 0x9E, 0x9C, 0x0D, 0xFE, 0xEA, 0xD3, 0x0D, 0xD9, 0x4B, 0xCF, 0x42, 0xEF, 0x8E }, ++ { 0x80, 0x83, 0x2C, 0x4A, 0x16, 0x77, 0xF5, 0xEA, 0x25, 0x60, 0xF6, 0x68, 0xE9, 0x35, 0x4D, 0xD3, 0x69, 0x97, 0xF0, 0x37, 0x28, 0xCF, 0xA5, 0x5E, 0x1B, 0x38, 0x33, 0x7C, 0x0C, 0x9E, 0xF8, 0x18 }, ++ { 0xAB, 0x37, 0xDD, 0xB6, 0x83, 0x13, 0x7E, 0x74, 0x08, 0x0D, 0x02, 0x6B, 0x59, 0x0B, 0x96, 0xAE, 0x9B, 0xB4, 0x47, 0x72, 0x2F, 0x30, 0x5A, 0x5A, 0xC5, 0x70, 0xEC, 0x1D, 0xF9, 0xB1, 0x74, 0x3C }, ++ { 0x3E, 0xE7, 0x35, 0xA6, 0x94, 0xC2, 0x55, 0x9B, 0x69, 0x3A, 0xA6, 0x86, 0x29, 0x36, 0x1E, 0x15, 0xD1, 0x22, 0x65, 0xAD, 0x6A, 0x3D, 0xED, 0xF4, 0x88, 0xB0, 0xB0, 0x0F, 0xAC, 0x97, 0x54, 0xBA }, ++ { 0xD6, 0xFC, 0xD2, 0x32, 0x19, 0xB6, 0x47, 0xE4, 0xCB, 0xD5, 0xEB, 0x2D, 0x0A, 0xD0, 0x1E, 0xC8, 0x83, 0x8A, 0x4B, 0x29, 0x01, 0xFC, 0x32, 0x5C, 0xC3, 0x70, 0x19, 0x81, 0xCA, 0x6C, 0x88, 0x8B }, ++ { 0x05, 0x20, 0xEC, 0x2F, 0x5B, 0xF7, 0xA7, 0x55, 0xDA, 0xCB, 0x50, 0xC6, 0xBF, 0x23, 0x3E, 0x35, 0x15, 0x43, 0x47, 0x63, 0xDB, 0x01, 0x39, 0xCC, 0xD9, 0xFA, 0xEF, 0xBB, 0x82, 0x07, 0x61, 0x2D }, ++ { 0xAF, 0xF3, 0xB7, 0x5F, 0x3F, 0x58, 0x12, 0x64, 0xD7, 0x66, 0x16, 0x62, 0xB9, 0x2F, 0x5A, 0xD3, 0x7C, 0x1D, 0x32, 0xBD, 0x45, 0xFF, 0x81, 0xA4, 0xED, 0x8A, 0xDC, 0x9E, 0xF3, 0x0D, 0xD9, 0x89 }, ++ { 0xD0, 0xDD, 0x65, 0x0B, 0xEF, 0xD3, 0xBA, 0x63, 0xDC, 0x25, 0x10, 0x2C, 0x62, 0x7C, 0x92, 0x1B, 0x9C, 0xBE, 0xB0, 0xB1, 0x30, 0x68, 0x69, 0x35, 0xB5, 0xC9, 0x27, 0xCB, 0x7C, 0xCD, 0x5E, 0x3B }, ++ { 0xE1, 0x14, 0x98, 0x16, 0xB1, 0x0A, 0x85, 0x14, 0xFB, 0x3E, 0x2C, 0xAB, 0x2C, 0x08, 0xBE, 0xE9, 0xF7, 0x3C, 0xE7, 0x62, 0x21, 0x70, 0x12, 0x46, 0xA5, 0x89, 0xBB, 0xB6, 0x73, 0x02, 0xD8, 0xA9 }, ++ { 0x7D, 0xA3, 0xF4, 0x41, 0xDE, 0x90, 0x54, 0x31, 0x7E, 0x72, 0xB5, 0xDB, 0xF9, 0x79, 0xDA, 0x01, 0xE6, 0xBC, 0xEE, 0xBB, 0x84, 0x78, 0xEA, 0xE6, 0xA2, 0x28, 0x49, 0xD9, 0x02, 0x92, 0x63, 0x5C }, ++ { 0x12, 0x30, 0xB1, 0xFC, 0x8A, 0x7D, 0x92, 0x15, 0xED, 0xC2, 0xD4, 0xA2, 0xDE, 0xCB, 0xDD, 0x0A, 0x6E, 0x21, 0x6C, 0x92, 0x42, 0x78, 0xC9, 0x1F, 0xC5, 0xD1, 0x0E, 0x7D, 0x60, 0x19, 0x2D, 0x94 }, ++ { 0x57, 0x50, 0xD7, 0x16, 0xB4, 0x80, 0x8F, 0x75, 0x1F, 0xEB, 0xC3, 0x88, 0x06, 0xBA, 0x17, 0x0B, 0xF6, 0xD5, 0x19, 0x9A, 0x78, 0x16, 0xBE, 0x51, 0x4E, 0x3F, 0x93, 0x2F, 0xBE, 0x0C, 0xB8, 0x71 }, ++ { 0x6F, 0xC5, 0x9B, 0x2F, 0x10, 0xFE, 0xBA, 0x95, 0x4A, 0xA6, 0x82, 0x0B, 0x3C, 0xA9, 0x87, 0xEE, 0x81, 0xD5, 0xCC, 0x1D, 0xA3, 0xC6, 0x3C, 0xE8, 0x27, 0x30, 0x1C, 0x56, 0x9D, 0xFB, 0x39, 0xCE }, ++ { 0xC7, 0xC3, 0xFE, 0x1E, 0xEB, 0xDC, 0x7B, 0x5A, 0x93, 0x93, 0x26, 0xE8, 0xDD, 0xB8, 0x3E, 0x8B, 0xF2, 0xB7, 0x80, 0xB6, 0x56, 0x78, 0xCB, 0x62, 0xF2, 0x08, 0xB0, 0x40, 0xAB, 0xDD, 0x35, 0xE2 }, ++ { 0x0C, 0x75, 0xC1, 0xA1, 0x5C, 0xF3, 0x4A, 0x31, 0x4E, 0xE4, 0x78, 0xF4, 0xA5, 0xCE, 0x0B, 0x8A, 0x6B, 0x36, 0x52, 0x8E, 0xF7, 0xA8, 0x20, 0x69, 0x6C, 0x3E, 0x42, 0x46, 0xC5, 0xA1, 0x58, 0x64 }, ++ { 0x21, 0x6D, 0xC1, 0x2A, 0x10, 0x85, 0x69, 0xA3, 0xC7, 0xCD, 0xDE, 0x4A, 0xED, 0x43, 0xA6, 0xC3, 0x30, 0x13, 0x9D, 0xDA, 0x3C, 0xCC, 0x4A, 0x10, 0x89, 0x05, 0xDB, 0x38, 0x61, 0x89, 0x90, 0x50 }, ++ { 0xA5, 0x7B, 0xE6, 0xAE, 0x67, 0x56, 0xF2, 0x8B, 0x02, 0xF5, 0x9D, 0xAD, 0xF7, 0xE0, 0xD7, 0xD8, 0x80, 0x7F, 0x10, 0xFA, 0x15, 0xCE, 0xD1, 0xAD, 0x35, 0x85, 0x52, 0x1A, 0x1D, 0x99, 0x5A, 0x89 }, ++ { 0x81, 0x6A, 0xEF, 0x87, 0x59, 0x53, 0x71, 0x6C, 0xD7, 0xA5, 0x81, 0xF7, 0x32, 0xF5, 0x3D, 0xD4, 0x35, 0xDA, 0xB6, 0x6D, 0x09, 0xC3, 0x61, 0xD2, 0xD6, 0x59, 0x2D, 0xE1, 0x77, 0x55, 0xD8, 0xA8 }, ++ { 0x9A, 0x76, 0x89, 0x32, 0x26, 0x69, 0x3B, 0x6E, 0xA9, 0x7E, 0x6A, 0x73, 0x8F, 0x9D, 0x10, 0xFB, 0x3D, 0x0B, 0x43, 0xAE, 0x0E, 0x8B, 0x7D, 0x81, 0x23, 0xEA, 0x76, 0xCE, 0x97, 0x98, 0x9C, 0x7E }, ++ { 0x8D, 0xAE, 0xDB, 0x9A, 0x27, 0x15, 0x29, 0xDB, 0xB7, 0xDC, 0x3B, 0x60, 0x7F, 0xE5, 0xEB, 0x2D, 0x32, 0x11, 0x77, 0x07, 0x58, 0xDD, 0x3B, 0x0A, 0x35, 0x93, 0xD2, 0xD7, 0x95, 0x4E, 0x2D, 0x5B }, ++ { 0x16, 0xDB, 0xC0, 0xAA, 0x5D, 0xD2, 0xC7, 0x74, 0xF5, 0x05, 0x10, 0x0F, 0x73, 0x37, 0x86, 0xD8, 0xA1, 0x75, 0xFC, 0xBB, 0xB5, 0x9C, 0x43, 0xE1, 0xFB, 0xFF, 0x3E, 0x1E, 0xAF, 0x31, 0xCB, 0x4A }, ++ { 0x86, 0x06, 0xCB, 0x89, 0x9C, 0x6A, 0xEA, 0xF5, 0x1B, 0x9D, 0xB0, 0xFE, 0x49, 0x24, 0xA9, 0xFD, 0x5D, 0xAB, 0xC1, 0x9F, 0x88, 0x26, 0xF2, 0xBC, 0x1C, 0x1D, 0x7D, 0xA1, 0x4D, 0x2C, 0x2C, 0x99 }, ++ { 0x84, 0x79, 0x73, 0x1A, 0xED, 0xA5, 0x7B, 0xD3, 0x7E, 0xAD, 0xB5, 0x1A, 0x50, 0x7E, 0x30, 0x7F, 0x3B, 0xD9, 0x5E, 0x69, 0xDB, 0xCA, 0x94, 0xF3, 0xBC, 0x21, 0x72, 0x60, 0x66, 0xAD, 0x6D, 0xFD }, ++ { 0x58, 0x47, 0x3A, 0x9E, 0xA8, 0x2E, 0xFA, 0x3F, 0x3B, 0x3D, 0x8F, 0xC8, 0x3E, 0xD8, 0x86, 0x31, 0x27, 0xB3, 0x3A, 0xE8, 0xDE, 0xAE, 0x63, 0x07, 0x20, 0x1E, 0xDB, 0x6D, 0xDE, 0x61, 0xDE, 0x29 }, ++ { 0x9A, 0x92, 0x55, 0xD5, 0x3A, 0xF1, 0x16, 0xDE, 0x8B, 0xA2, 0x7C, 0xE3, 0x5B, 0x4C, 0x7E, 0x15, 0x64, 0x06, 0x57, 0xA0, 0xFC, 0xB8, 0x88, 0xC7, 0x0D, 0x95, 0x43, 0x1D, 0xAC, 0xD8, 0xF8, 0x30 }, ++ { 0x9E, 0xB0, 0x5F, 0xFB, 0xA3, 0x9F, 0xD8, 0x59, 0x6A, 0x45, 0x49, 0x3E, 0x18, 0xD2, 0x51, 0x0B, 0xF3, 0xEF, 0x06, 0x5C, 0x51, 0xD6, 0xE1, 0x3A, 0xBE, 0x66, 0xAA, 0x57, 0xE0, 0x5C, 0xFD, 0xB7 }, ++ { 0x81, 0xDC, 0xC3, 0xA5, 0x05, 0xEA, 0xCE, 0x3F, 0x87, 0x9D, 0x8F, 0x70, 0x27, 0x76, 0x77, 0x0F, 0x9D, 0xF5, 0x0E, 0x52, 0x1D, 0x14, 0x28, 0xA8, 0x5D, 0xAF, 0x04, 0xF9, 0xAD, 0x21, 0x50, 0xE0 }, ++ { 0xE3, 0xE3, 0xC4, 0xAA, 0x3A, 0xCB, 0xBC, 0x85, 0x33, 0x2A, 0xF9, 0xD5, 0x64, 0xBC, 0x24, 0x16, 0x5E, 0x16, 0x87, 0xF6, 0xB1, 0xAD, 0xCB, 0xFA, 0xE7, 0x7A, 0x8F, 0x03, 0xC7, 0x2A, 0xC2, 0x8C }, ++ { 0x67, 0x46, 0xC8, 0x0B, 0x4E, 0xB5, 0x6A, 0xEA, 0x45, 0xE6, 0x4E, 0x72, 0x89, 0xBB, 0xA3, 0xED, 0xBF, 0x45, 0xEC, 0xF8, 0x20, 0x64, 0x81, 0xFF, 0x63, 0x02, 0x12, 0x29, 0x84, 0xCD, 0x52, 0x6A }, ++ { 0x2B, 0x62, 0x8E, 0x52, 0x76, 0x4D, 0x7D, 0x62, 0xC0, 0x86, 0x8B, 0x21, 0x23, 0x57, 0xCD, 0xD1, 0x2D, 0x91, 0x49, 0x82, 0x2F, 0x4E, 0x98, 0x45, 0xD9, 0x18, 0xA0, 0x8D, 0x1A, 0xE9, 0x90, 0xC0 }, ++ { 0xE4, 0xBF, 0xE8, 0x0D, 0x58, 0xC9, 0x19, 0x94, 0x61, 0x39, 0x09, 0xDC, 0x4B, 0x1A, 0x12, 0x49, 0x68, 0x96, 0xC0, 0x04, 0xAF, 0x7B, 0x57, 0x01, 0x48, 0x3D, 0xE4, 0x5D, 0x28, 0x23, 0xD7, 0x8E }, ++ { 0xEB, 0xB4, 0xBA, 0x15, 0x0C, 0xEF, 0x27, 0x34, 0x34, 0x5B, 0x5D, 0x64, 0x1B, 0xBE, 0xD0, 0x3A, 0x21, 0xEA, 0xFA, 0xE9, 0x33, 0xC9, 0x9E, 0x00, 0x92, 0x12, 0xEF, 0x04, 0x57, 0x4A, 0x85, 0x30 }, ++ { 0x39, 0x66, 0xEC, 0x73, 0xB1, 0x54, 0xAC, 0xC6, 0x97, 0xAC, 0x5C, 0xF5, 0xB2, 0x4B, 0x40, 0xBD, 0xB0, 0xDB, 0x9E, 0x39, 0x88, 0x36, 0xD7, 0x6D, 0x4B, 0x88, 0x0E, 0x3B, 0x2A, 0xF1, 0xAA, 0x27 }, ++ { 0xEF, 0x7E, 0x48, 0x31, 0xB3, 0xA8, 0x46, 0x36, 0x51, 0x8D, 0x6E, 0x4B, 0xFC, 0xE6, 0x4A, 0x43, 0xDB, 0x2A, 0x5D, 0xDA, 0x9C, 0xCA, 0x2B, 0x44, 0xF3, 0x90, 0x33, 0xBD, 0xC4, 0x0D, 0x62, 0x43 }, ++ { 0x7A, 0xBF, 0x6A, 0xCF, 0x5C, 0x8E, 0x54, 0x9D, 0xDB, 0xB1, 0x5A, 0xE8, 0xD8, 0xB3, 0x88, 0xC1, 0xC1, 0x97, 0xE6, 0x98, 0x73, 0x7C, 0x97, 0x85, 0x50, 0x1E, 0xD1, 0xF9, 0x49, 0x30, 0xB7, 0xD9 }, ++ { 0x88, 0x01, 0x8D, 0xED, 0x66, 0x81, 0x3F, 0x0C, 0xA9, 0x5D, 0xEF, 0x47, 0x4C, 0x63, 0x06, 0x92, 0x01, 0x99, 0x67, 0xB9, 0xE3, 0x68, 0x88, 0xDA, 0xDD, 0x94, 0x12, 0x47, 0x19, 0xB6, 0x82, 0xF6 }, ++ { 0x39, 0x30, 0x87, 0x6B, 0x9F, 0xC7, 0x52, 0x90, 0x36, 0xB0, 0x08, 0xB1, 0xB8, 0xBB, 0x99, 0x75, 0x22, 0xA4, 0x41, 0x63, 0x5A, 0x0C, 0x25, 0xEC, 0x02, 0xFB, 0x6D, 0x90, 0x26, 0xE5, 0x5A, 0x97 }, ++ { 0x0A, 0x40, 0x49, 0xD5, 0x7E, 0x83, 0x3B, 0x56, 0x95, 0xFA, 0xC9, 0x3D, 0xD1, 0xFB, 0xEF, 0x31, 0x66, 0xB4, 0x4B, 0x12, 0xAD, 0x11, 0x24, 0x86, 0x62, 0x38, 0x3A, 0xE0, 0x51, 0xE1, 0x58, 0x27 }, ++ { 0x81, 0xDC, 0xC0, 0x67, 0x8B, 0xB6, 0xA7, 0x65, 0xE4, 0x8C, 0x32, 0x09, 0x65, 0x4F, 0xE9, 0x00, 0x89, 0xCE, 0x44, 0xFF, 0x56, 0x18, 0x47, 0x7E, 0x39, 0xAB, 0x28, 0x64, 0x76, 0xDF, 0x05, 0x2B }, ++ { 0xE6, 0x9B, 0x3A, 0x36, 0xA4, 0x46, 0x19, 0x12, 0xDC, 0x08, 0x34, 0x6B, 0x11, 0xDD, 0xCB, 0x9D, 0xB7, 0x96, 0xF8, 0x85, 0xFD, 0x01, 0x93, 0x6E, 0x66, 0x2F, 0xE2, 0x92, 0x97, 0xB0, 0x99, 0xA4 }, ++ { 0x5A, 0xC6, 0x50, 0x3B, 0x0D, 0x8D, 0xA6, 0x91, 0x76, 0x46, 0xE6, 0xDC, 0xC8, 0x7E, 0xDC, 0x58, 0xE9, 0x42, 0x45, 0x32, 0x4C, 0xC2, 0x04, 0xF4, 0xDD, 0x4A, 0xF0, 0x15, 0x63, 0xAC, 0xD4, 0x27 }, ++ { 0xDF, 0x6D, 0xDA, 0x21, 0x35, 0x9A, 0x30, 0xBC, 0x27, 0x17, 0x80, 0x97, 0x1C, 0x1A, 0xBD, 0x56, 0xA6, 0xEF, 0x16, 0x7E, 0x48, 0x08, 0x87, 0x88, 0x8E, 0x73, 0xA8, 0x6D, 0x3B, 0xF6, 0x05, 0xE9 }, ++ { 0xE8, 0xE6, 0xE4, 0x70, 0x71, 0xE7, 0xB7, 0xDF, 0x25, 0x80, 0xF2, 0x25, 0xCF, 0xBB, 0xED, 0xF8, 0x4C, 0xE6, 0x77, 0x46, 0x62, 0x66, 0x28, 0xD3, 0x30, 0x97, 0xE4, 0xB7, 0xDC, 0x57, 0x11, 0x07 }, ++ { 0x53, 0xE4, 0x0E, 0xAD, 0x62, 0x05, 0x1E, 0x19, 0xCB, 0x9B, 0xA8, 0x13, 0x3E, 0x3E, 0x5C, 0x1C, 0xE0, 0x0D, 0xDC, 0xAD, 0x8A, 0xCF, 0x34, 0x2A, 0x22, 0x43, 0x60, 0xB0, 0xAC, 0xC1, 0x47, 0x77 }, ++ { 0x9C, 0xCD, 0x53, 0xFE, 0x80, 0xBE, 0x78, 0x6A, 0xA9, 0x84, 0x63, 0x84, 0x62, 0xFB, 0x28, 0xAF, 0xDF, 0x12, 0x2B, 0x34, 0xD7, 0x8F, 0x46, 0x87, 0xEC, 0x63, 0x2B, 0xB1, 0x9D, 0xE2, 0x37, 0x1A }, ++ { 0xCB, 0xD4, 0x80, 0x52, 0xC4, 0x8D, 0x78, 0x84, 0x66, 0xA3, 0xE8, 0x11, 0x8C, 0x56, 0xC9, 0x7F, 0xE1, 0x46, 0xE5, 0x54, 0x6F, 0xAA, 0xF9, 0x3E, 0x2B, 0xC3, 0xC4, 0x7E, 0x45, 0x93, 0x97, 0x53 }, ++ { 0x25, 0x68, 0x83, 0xB1, 0x4E, 0x2A, 0xF4, 0x4D, 0xAD, 0xB2, 0x8E, 0x1B, 0x34, 0xB2, 0xAC, 0x0F, 0x0F, 0x4C, 0x91, 0xC3, 0x4E, 0xC9, 0x16, 0x9E, 0x29, 0x03, 0x61, 0x58, 0xAC, 0xAA, 0x95, 0xB9 }, ++ { 0x44, 0x71, 0xB9, 0x1A, 0xB4, 0x2D, 0xB7, 0xC4, 0xDD, 0x84, 0x90, 0xAB, 0x95, 0xA2, 0xEE, 0x8D, 0x04, 0xE3, 0xEF, 0x5C, 0x3D, 0x6F, 0xC7, 0x1A, 0xC7, 0x4B, 0x2B, 0x26, 0x91, 0x4D, 0x16, 0x41 }, ++ { 0xA5, 0xEB, 0x08, 0x03, 0x8F, 0x8F, 0x11, 0x55, 0xED, 0x86, 0xE6, 0x31, 0x90, 0x6F, 0xC1, 0x30, 0x95, 0xF6, 0xBB, 0xA4, 0x1D, 0xE5, 0xD4, 0xE7, 0x95, 0x75, 0x8E, 0xC8, 0xC8, 0xDF, 0x8A, 0xF1 }, ++ { 0xDC, 0x1D, 0xB6, 0x4E, 0xD8, 0xB4, 0x8A, 0x91, 0x0E, 0x06, 0x0A, 0x6B, 0x86, 0x63, 0x74, 0xC5, 0x78, 0x78, 0x4E, 0x9A, 0xC4, 0x9A, 0xB2, 0x77, 0x40, 0x92, 0xAC, 0x71, 0x50, 0x19, 0x34, 0xAC }, ++ { 0x28, 0x54, 0x13, 0xB2, 0xF2, 0xEE, 0x87, 0x3D, 0x34, 0x31, 0x9E, 0xE0, 0xBB, 0xFB, 0xB9, 0x0F, 0x32, 0xDA, 0x43, 0x4C, 0xC8, 0x7E, 0x3D, 0xB5, 0xED, 0x12, 0x1B, 0xB3, 0x98, 0xED, 0x96, 0x4B }, ++ { 0x02, 0x16, 0xE0, 0xF8, 0x1F, 0x75, 0x0F, 0x26, 0xF1, 0x99, 0x8B, 0xC3, 0x93, 0x4E, 0x3E, 0x12, 0x4C, 0x99, 0x45, 0xE6, 0x85, 0xA6, 0x0B, 0x25, 0xE8, 0xFB, 0xD9, 0x62, 0x5A, 0xB6, 0xB5, 0x99 }, ++ { 0x38, 0xC4, 0x10, 0xF5, 0xB9, 0xD4, 0x07, 0x20, 0x50, 0x75, 0x5B, 0x31, 0xDC, 0xA8, 0x9F, 0xD5, 0x39, 0x5C, 0x67, 0x85, 0xEE, 0xB3, 0xD7, 0x90, 0xF3, 0x20, 0xFF, 0x94, 0x1C, 0x5A, 0x93, 0xBF }, ++ { 0xF1, 0x84, 0x17, 0xB3, 0x9D, 0x61, 0x7A, 0xB1, 0xC1, 0x8F, 0xDF, 0x91, 0xEB, 0xD0, 0xFC, 0x6D, 0x55, 0x16, 0xBB, 0x34, 0xCF, 0x39, 0x36, 0x40, 0x37, 0xBC, 0xE8, 0x1F, 0xA0, 0x4C, 0xEC, 0xB1 }, ++ { 0x1F, 0xA8, 0x77, 0xDE, 0x67, 0x25, 0x9D, 0x19, 0x86, 0x3A, 0x2A, 0x34, 0xBC, 0xC6, 0x96, 0x2A, 0x2B, 0x25, 0xFC, 0xBF, 0x5C, 0xBE, 0xCD, 0x7E, 0xDE, 0x8F, 0x1F, 0xA3, 0x66, 0x88, 0xA7, 0x96 }, ++ { 0x5B, 0xD1, 0x69, 0xE6, 0x7C, 0x82, 0xC2, 0xC2, 0xE9, 0x8E, 0xF7, 0x00, 0x8B, 0xDF, 0x26, 0x1F, 0x2D, 0xDF, 0x30, 0xB1, 0xC0, 0x0F, 0x9E, 0x7F, 0x27, 0x5B, 0xB3, 0xE8, 0xA2, 0x8D, 0xC9, 0xA2 }, ++ { 0xC8, 0x0A, 0xBE, 0xEB, 0xB6, 0x69, 0xAD, 0x5D, 0xEE, 0xB5, 0xF5, 0xEC, 0x8E, 0xA6, 0xB7, 0xA0, 0x5D, 0xDF, 0x7D, 0x31, 0xEC, 0x4C, 0x0A, 0x2E, 0xE2, 0x0B, 0x0B, 0x98, 0xCA, 0xEC, 0x67, 0x46 }, ++ { 0xE7, 0x6D, 0x3F, 0xBD, 0xA5, 0xBA, 0x37, 0x4E, 0x6B, 0xF8, 0xE5, 0x0F, 0xAD, 0xC3, 0xBB, 0xB9, 0xBA, 0x5C, 0x20, 0x6E, 0xBD, 0xEC, 0x89, 0xA3, 0xA5, 0x4C, 0xF3, 0xDD, 0x84, 0xA0, 0x70, 0x16 }, ++ { 0x7B, 0xBA, 0x9D, 0xC5, 0xB5, 0xDB, 0x20, 0x71, 0xD1, 0x77, 0x52, 0xB1, 0x04, 0x4C, 0x1E, 0xCE, 0xD9, 0x6A, 0xAF, 0x2D, 0xD4, 0x6E, 0x9B, 0x43, 0x37, 0x50, 0xE8, 0xEA, 0x0D, 0xCC, 0x18, 0x70 }, ++ { 0xF2, 0x9B, 0x1B, 0x1A, 0xB9, 0xBA, 0xB1, 0x63, 0x01, 0x8E, 0xE3, 0xDA, 0x15, 0x23, 0x2C, 0xCA, 0x78, 0xEC, 0x52, 0xDB, 0xC3, 0x4E, 0xDA, 0x5B, 0x82, 0x2E, 0xC1, 0xD8, 0x0F, 0xC2, 0x1B, 0xD0 }, ++ { 0x9E, 0xE3, 0xE3, 0xE7, 0xE9, 0x00, 0xF1, 0xE1, 0x1D, 0x30, 0x8C, 0x4B, 0x2B, 0x30, 0x76, 0xD2, 0x72, 0xCF, 0x70, 0x12, 0x4F, 0x9F, 0x51, 0xE1, 0xDA, 0x60, 0xF3, 0x78, 0x46, 0xCD, 0xD2, 0xF4 }, ++ { 0x70, 0xEA, 0x3B, 0x01, 0x76, 0x92, 0x7D, 0x90, 0x96, 0xA1, 0x85, 0x08, 0xCD, 0x12, 0x3A, 0x29, 0x03, 0x25, 0x92, 0x0A, 0x9D, 0x00, 0xA8, 0x9B, 0x5D, 0xE0, 0x42, 0x73, 0xFB, 0xC7, 0x6B, 0x85 }, ++ { 0x67, 0xDE, 0x25, 0xC0, 0x2A, 0x4A, 0xAB, 0xA2, 0x3B, 0xDC, 0x97, 0x3C, 0x8B, 0xB0, 0xB5, 0x79, 0x6D, 0x47, 0xCC, 0x06, 0x59, 0xD4, 0x3D, 0xFF, 0x1F, 0x97, 0xDE, 0x17, 0x49, 0x63, 0xB6, 0x8E }, ++ { 0xB2, 0x16, 0x8E, 0x4E, 0x0F, 0x18, 0xB0, 0xE6, 0x41, 0x00, 0xB5, 0x17, 0xED, 0x95, 0x25, 0x7D, 0x73, 0xF0, 0x62, 0x0D, 0xF8, 0x85, 0xC1, 0x3D, 0x2E, 0xCF, 0x79, 0x36, 0x7B, 0x38, 0x4C, 0xEE }, ++ { 0x2E, 0x7D, 0xEC, 0x24, 0x28, 0x85, 0x3B, 0x2C, 0x71, 0x76, 0x07, 0x45, 0x54, 0x1F, 0x7A, 0xFE, 0x98, 0x25, 0xB5, 0xDD, 0x77, 0xDF, 0x06, 0x51, 0x1D, 0x84, 0x41, 0xA9, 0x4B, 0xAC, 0xC9, 0x27 }, ++ { 0xCA, 0x9F, 0xFA, 0xC4, 0xC4, 0x3F, 0x0B, 0x48, 0x46, 0x1D, 0xC5, 0xC2, 0x63, 0xBE, 0xA3, 0xF6, 0xF0, 0x06, 0x11, 0xCE, 0xAC, 0xAB, 0xF6, 0xF8, 0x95, 0xBA, 0x2B, 0x01, 0x01, 0xDB, 0xB6, 0x8D }, ++ { 0x74, 0x10, 0xD4, 0x2D, 0x8F, 0xD1, 0xD5, 0xE9, 0xD2, 0xF5, 0x81, 0x5C, 0xB9, 0x34, 0x17, 0x99, 0x88, 0x28, 0xEF, 0x3C, 0x42, 0x30, 0xBF, 0xBD, 0x41, 0x2D, 0xF0, 0xA4, 0xA7, 0xA2, 0x50, 0x7A }, ++ { 0x50, 0x10, 0xF6, 0x84, 0x51, 0x6D, 0xCC, 0xD0, 0xB6, 0xEE, 0x08, 0x52, 0xC2, 0x51, 0x2B, 0x4D, 0xC0, 0x06, 0x6C, 0xF0, 0xD5, 0x6F, 0x35, 0x30, 0x29, 0x78, 0xDB, 0x8A, 0xE3, 0x2C, 0x6A, 0x81 }, ++ { 0xAC, 0xAA, 0xB5, 0x85, 0xF7, 0xB7, 0x9B, 0x71, 0x99, 0x35, 0xCE, 0xB8, 0x95, 0x23, 0xDD, 0xC5, 0x48, 0x27, 0xF7, 0x5C, 0x56, 0x88, 0x38, 0x56, 0x15, 0x4A, 0x56, 0xCD, 0xCD, 0x5E, 0xE9, 0x88 }, ++ { 0x66, 0x6D, 0xE5, 0xD1, 0x44, 0x0F, 0xEE, 0x73, 0x31, 0xAA, 0xF0, 0x12, 0x3A, 0x62, 0xEF, 0x2D, 0x8B, 0xA5, 0x74, 0x53, 0xA0, 0x76, 0x96, 0x35, 0xAC, 0x6C, 0xD0, 0x1E, 0x63, 0x3F, 0x77, 0x12 }, ++ { 0xA6, 0xF9, 0x86, 0x58, 0xF6, 0xEA, 0xBA, 0xF9, 0x02, 0xD8, 0xB3, 0x87, 0x1A, 0x4B, 0x10, 0x1D, 0x16, 0x19, 0x6E, 0x8A, 0x4B, 0x24, 0x1E, 0x15, 0x58, 0xFE, 0x29, 0x96, 0x6E, 0x10, 0x3E, 0x8D }, ++ { 0x89, 0x15, 0x46, 0xA8, 0xB2, 0x9F, 0x30, 0x47, 0xDD, 0xCF, 0xE5, 0xB0, 0x0E, 0x45, 0xFD, 0x55, 0x75, 0x63, 0x73, 0x10, 0x5E, 0xA8, 0x63, 0x7D, 0xFC, 0xFF, 0x54, 0x7B, 0x6E, 0xA9, 0x53, 0x5F }, ++ { 0x18, 0xDF, 0xBC, 0x1A, 0xC5, 0xD2, 0x5B, 0x07, 0x61, 0x13, 0x7D, 0xBD, 0x22, 0xC1, 0x7C, 0x82, 0x9D, 0x0F, 0x0E, 0xF1, 0xD8, 0x23, 0x44, 0xE9, 0xC8, 0x9C, 0x28, 0x66, 0x94, 0xDA, 0x24, 0xE8 }, ++ { 0xB5, 0x4B, 0x9B, 0x67, 0xF8, 0xFE, 0xD5, 0x4B, 0xBF, 0x5A, 0x26, 0x66, 0xDB, 0xDF, 0x4B, 0x23, 0xCF, 0xF1, 0xD1, 0xB6, 0xF4, 0xAF, 0xC9, 0x85, 0xB2, 0xE6, 0xD3, 0x30, 0x5A, 0x9F, 0xF8, 0x0F }, ++ { 0x7D, 0xB4, 0x42, 0xE1, 0x32, 0xBA, 0x59, 0xBC, 0x12, 0x89, 0xAA, 0x98, 0xB0, 0xD3, 0xE8, 0x06, 0x00, 0x4F, 0x8E, 0xC1, 0x28, 0x11, 0xAF, 0x1E, 0x2E, 0x33, 0xC6, 0x9B, 0xFD, 0xE7, 0x29, 0xE1 }, ++ { 0x25, 0x0F, 0x37, 0xCD, 0xC1, 0x5E, 0x81, 0x7D, 0x2F, 0x16, 0x0D, 0x99, 0x56, 0xC7, 0x1F, 0xE3, 0xEB, 0x5D, 0xB7, 0x45, 0x56, 0xE4, 0xAD, 0xF9, 0xA4, 0xFF, 0xAF, 0xBA, 0x74, 0x01, 0x03, 0x96 }, ++ { 0x4A, 0xB8, 0xA3, 0xDD, 0x1D, 0xDF, 0x8A, 0xD4, 0x3D, 0xAB, 0x13, 0xA2, 0x7F, 0x66, 0xA6, 0x54, 0x4F, 0x29, 0x05, 0x97, 0xFA, 0x96, 0x04, 0x0E, 0x0E, 0x1D, 0xB9, 0x26, 0x3A, 0xA4, 0x79, 0xF8 }, ++ { 0xEE, 0x61, 0x72, 0x7A, 0x07, 0x66, 0xDF, 0x93, 0x9C, 0xCD, 0xC8, 0x60, 0x33, 0x40, 0x44, 0xC7, 0x9A, 0x3C, 0x9B, 0x15, 0x62, 0x00, 0xBC, 0x3A, 0xA3, 0x29, 0x73, 0x48, 0x3D, 0x83, 0x41, 0xAE }, ++ { 0x3F, 0x68, 0xC7, 0xEC, 0x63, 0xAC, 0x11, 0xEB, 0xB9, 0x8F, 0x94, 0xB3, 0x39, 0xB0, 0x5C, 0x10, 0x49, 0x84, 0xFD, 0xA5, 0x01, 0x03, 0x06, 0x01, 0x44, 0xE5, 0xA2, 0xBF, 0xCC, 0xC9, 0xDA, 0x95 }, ++ { 0x05, 0x6F, 0x29, 0x81, 0x6B, 0x8A, 0xF8, 0xF5, 0x66, 0x82, 0xBC, 0x4D, 0x7C, 0xF0, 0x94, 0x11, 0x1D, 0xA7, 0x73, 0x3E, 0x72, 0x6C, 0xD1, 0x3D, 0x6B, 0x3E, 0x8E, 0xA0, 0x3E, 0x92, 0xA0, 0xD5 }, ++ { 0xF5, 0xEC, 0x43, 0xA2, 0x8A, 0xCB, 0xEF, 0xF1, 0xF3, 0x31, 0x8A, 0x5B, 0xCA, 0xC7, 0xC6, 0x6D, 0xDB, 0x52, 0x30, 0xB7, 0x9D, 0xB2, 0xD1, 0x05, 0xBC, 0xBE, 0x15, 0xF3, 0xC1, 0x14, 0x8D, 0x69 }, ++ { 0x2A, 0x69, 0x60, 0xAD, 0x1D, 0x8D, 0xD5, 0x47, 0x55, 0x5C, 0xFB, 0xD5, 0xE4, 0x60, 0x0F, 0x1E, 0xAA, 0x1C, 0x8E, 0xDA, 0x34, 0xDE, 0x03, 0x74, 0xEC, 0x4A, 0x26, 0xEA, 0xAA, 0xA3, 0x3B, 0x4E }, ++ { 0xDC, 0xC1, 0xEA, 0x7B, 0xAA, 0xB9, 0x33, 0x84, 0xF7, 0x6B, 0x79, 0x68, 0x66, 0x19, 0x97, 0x54, 0x74, 0x2F, 0x7B, 0x96, 0xD6, 0xB4, 0xC1, 0x20, 0x16, 0x5C, 0x04, 0xA6, 0xC4, 0xF5, 0xCE, 0x10 }, ++ { 0x13, 0xD5, 0xDF, 0x17, 0x92, 0x21, 0x37, 0x9C, 0x6A, 0x78, 0xC0, 0x7C, 0x79, 0x3F, 0xF5, 0x34, 0x87, 0xCA, 0xE6, 0xBF, 0x9F, 0xE8, 0x82, 0x54, 0x1A, 0xB0, 0xE7, 0x35, 0xE3, 0xEA, 0xDA, 0x3B }, ++ { 0x8C, 0x59, 0xE4, 0x40, 0x76, 0x41, 0xA0, 0x1E, 0x8F, 0xF9, 0x1F, 0x99, 0x80, 0xDC, 0x23, 0x6F, 0x4E, 0xCD, 0x6F, 0xCF, 0x52, 0x58, 0x9A, 0x09, 0x9A, 0x96, 0x16, 0x33, 0x96, 0x77, 0x14, 0xE1 }, ++ { 0x83, 0x3B, 0x1A, 0xC6, 0xA2, 0x51, 0xFD, 0x08, 0xFD, 0x6D, 0x90, 0x8F, 0xEA, 0x2A, 0x4E, 0xE1, 0xE0, 0x40, 0xBC, 0xA9, 0x3F, 0xC1, 0xA3, 0x8E, 0xC3, 0x82, 0x0E, 0x0C, 0x10, 0xBD, 0x82, 0xEA }, ++ { 0xA2, 0x44, 0xF9, 0x27, 0xF3, 0xB4, 0x0B, 0x8F, 0x6C, 0x39, 0x15, 0x70, 0xC7, 0x65, 0x41, 0x8F, 0x2F, 0x6E, 0x70, 0x8E, 0xAC, 0x90, 0x06, 0xC5, 0x1A, 0x7F, 0xEF, 0xF4, 0xAF, 0x3B, 0x2B, 0x9E }, ++ { 0x3D, 0x99, 0xED, 0x95, 0x50, 0xCF, 0x11, 0x96, 0xE6, 0xC4, 0xD2, 0x0C, 0x25, 0x96, 0x20, 0xF8, 0x58, 0xC3, 0xD7, 0x03, 0x37, 0x4C, 0x12, 0x8C, 0xE7, 0xB5, 0x90, 0x31, 0x0C, 0x83, 0x04, 0x6D }, ++ { 0x2B, 0x35, 0xC4, 0x7D, 0x7B, 0x87, 0x76, 0x1F, 0x0A, 0xE4, 0x3A, 0xC5, 0x6A, 0xC2, 0x7B, 0x9F, 0x25, 0x83, 0x03, 0x67, 0xB5, 0x95, 0xBE, 0x8C, 0x24, 0x0E, 0x94, 0x60, 0x0C, 0x6E, 0x33, 0x12 }, ++ { 0x5D, 0x11, 0xED, 0x37, 0xD2, 0x4D, 0xC7, 0x67, 0x30, 0x5C, 0xB7, 0xE1, 0x46, 0x7D, 0x87, 0xC0, 0x65, 0xAC, 0x4B, 0xC8, 0xA4, 0x26, 0xDE, 0x38, 0x99, 0x1F, 0xF5, 0x9A, 0xA8, 0x73, 0x5D, 0x02 }, ++ { 0xB8, 0x36, 0x47, 0x8E, 0x1C, 0xA0, 0x64, 0x0D, 0xCE, 0x6F, 0xD9, 0x10, 0xA5, 0x09, 0x62, 0x72, 0xC8, 0x33, 0x09, 0x90, 0xCD, 0x97, 0x86, 0x4A, 0xC2, 0xBF, 0x14, 0xEF, 0x6B, 0x23, 0x91, 0x4A }, ++ { 0x91, 0x00, 0xF9, 0x46, 0xD6, 0xCC, 0xDE, 0x3A, 0x59, 0x7F, 0x90, 0xD3, 0x9F, 0xC1, 0x21, 0x5B, 0xAD, 0xDC, 0x74, 0x13, 0x64, 0x3D, 0x85, 0xC2, 0x1C, 0x3E, 0xEE, 0x5D, 0x2D, 0xD3, 0x28, 0x94 }, ++ { 0xDA, 0x70, 0xEE, 0xDD, 0x23, 0xE6, 0x63, 0xAA, 0x1A, 0x74, 0xB9, 0x76, 0x69, 0x35, 0xB4, 0x79, 0x22, 0x2A, 0x72, 0xAF, 0xBA, 0x5C, 0x79, 0x51, 0x58, 0xDA, 0xD4, 0x1A, 0x3B, 0xD7, 0x7E, 0x40 }, ++ { 0xF0, 0x67, 0xED, 0x6A, 0x0D, 0xBD, 0x43, 0xAA, 0x0A, 0x92, 0x54, 0xE6, 0x9F, 0xD6, 0x6B, 0xDD, 0x8A, 0xCB, 0x87, 0xDE, 0x93, 0x6C, 0x25, 0x8C, 0xFB, 0x02, 0x28, 0x5F, 0x2C, 0x11, 0xFA, 0x79 }, ++ { 0x71, 0x5C, 0x99, 0xC7, 0xD5, 0x75, 0x80, 0xCF, 0x97, 0x53, 0xB4, 0xC1, 0xD7, 0x95, 0xE4, 0x5A, 0x83, 0xFB, 0xB2, 0x28, 0xC0, 0xD3, 0x6F, 0xBE, 0x20, 0xFA, 0xF3, 0x9B, 0xDD, 0x6D, 0x4E, 0x85 }, ++ { 0xE4, 0x57, 0xD6, 0xAD, 0x1E, 0x67, 0xCB, 0x9B, 0xBD, 0x17, 0xCB, 0xD6, 0x98, 0xFA, 0x6D, 0x7D, 0xAE, 0x0C, 0x9B, 0x7A, 0xD6, 0xCB, 0xD6, 0x53, 0x96, 0x34, 0xE3, 0x2A, 0x71, 0x9C, 0x84, 0x92 }, ++ { 0xEC, 0xE3, 0xEA, 0x81, 0x03, 0xE0, 0x24, 0x83, 0xC6, 0x4A, 0x70, 0xA4, 0xBD, 0xCE, 0xE8, 0xCE, 0xB6, 0x27, 0x8F, 0x25, 0x33, 0xF3, 0xF4, 0x8D, 0xBE, 0xED, 0xFB, 0xA9, 0x45, 0x31, 0xD4, 0xAE }, ++ { 0x38, 0x8A, 0xA5, 0xD3, 0x66, 0x7A, 0x97, 0xC6, 0x8D, 0x3D, 0x56, 0xF8, 0xF3, 0xEE, 0x8D, 0x3D, 0x36, 0x09, 0x1F, 0x17, 0xFE, 0x5D, 0x1B, 0x0D, 0x5D, 0x84, 0xC9, 0x3B, 0x2F, 0xFE, 0x40, 0xBD }, ++ { 0x8B, 0x6B, 0x31, 0xB9, 0xAD, 0x7C, 0x3D, 0x5C, 0xD8, 0x4B, 0xF9, 0x89, 0x47, 0xB9, 0xCD, 0xB5, 0x9D, 0xF8, 0xA2, 0x5F, 0xF7, 0x38, 0x10, 0x10, 0x13, 0xBE, 0x4F, 0xD6, 0x5E, 0x1D, 0xD1, 0xA3 }, ++ { 0x06, 0x62, 0x91, 0xF6, 0xBB, 0xD2, 0x5F, 0x3C, 0x85, 0x3D, 0xB7, 0xD8, 0xB9, 0x5C, 0x9A, 0x1C, 0xFB, 0x9B, 0xF1, 0xC1, 0xC9, 0x9F, 0xB9, 0x5A, 0x9B, 0x78, 0x69, 0xD9, 0x0F, 0x1C, 0x29, 0x03 }, ++ { 0xA7, 0x07, 0xEF, 0xBC, 0xCD, 0xCE, 0xED, 0x42, 0x96, 0x7A, 0x66, 0xF5, 0x53, 0x9B, 0x93, 0xED, 0x75, 0x60, 0xD4, 0x67, 0x30, 0x40, 0x16, 0xC4, 0x78, 0x0D, 0x77, 0x55, 0xA5, 0x65, 0xD4, 0xC4 }, ++ { 0x38, 0xC5, 0x3D, 0xFB, 0x70, 0xBE, 0x7E, 0x79, 0x2B, 0x07, 0xA6, 0xA3, 0x5B, 0x8A, 0x6A, 0x0A, 0xBA, 0x02, 0xC5, 0xC5, 0xF3, 0x8B, 0xAF, 0x5C, 0x82, 0x3F, 0xDF, 0xD9, 0xE4, 0x2D, 0x65, 0x7E }, ++ { 0xF2, 0x91, 0x13, 0x86, 0x50, 0x1D, 0x9A, 0xB9, 0xD7, 0x20, 0xCF, 0x8A, 0xD1, 0x05, 0x03, 0xD5, 0x63, 0x4B, 0xF4, 0xB7, 0xD1, 0x2B, 0x56, 0xDF, 0xB7, 0x4F, 0xEC, 0xC6, 0xE4, 0x09, 0x3F, 0x68 }, ++ { 0xC6, 0xF2, 0xBD, 0xD5, 0x2B, 0x81, 0xE6, 0xE4, 0xF6, 0x59, 0x5A, 0xBD, 0x4D, 0x7F, 0xB3, 0x1F, 0x65, 0x11, 0x69, 0xD0, 0x0F, 0xF3, 0x26, 0x92, 0x6B, 0x34, 0x94, 0x7B, 0x28, 0xA8, 0x39, 0x59 }, ++ { 0x29, 0x3D, 0x94, 0xB1, 0x8C, 0x98, 0xBB, 0x32, 0x23, 0x36, 0x6B, 0x8C, 0xE7, 0x4C, 0x28, 0xFB, 0xDF, 0x28, 0xE1, 0xF8, 0x4A, 0x33, 0x50, 0xB0, 0xEB, 0x2D, 0x18, 0x04, 0xA5, 0x77, 0x57, 0x9B }, ++ { 0x2C, 0x2F, 0xA5, 0xC0, 0xB5, 0x15, 0x33, 0x16, 0x5B, 0xC3, 0x75, 0xC2, 0x2E, 0x27, 0x81, 0x76, 0x82, 0x70, 0xA3, 0x83, 0x98, 0x5D, 0x13, 0xBD, 0x6B, 0x67, 0xB6, 0xFD, 0x67, 0xF8, 0x89, 0xEB }, ++ { 0xCA, 0xA0, 0x9B, 0x82, 0xB7, 0x25, 0x62, 0xE4, 0x3F, 0x4B, 0x22, 0x75, 0xC0, 0x91, 0x91, 0x8E, 0x62, 0x4D, 0x91, 0x16, 0x61, 0xCC, 0x81, 0x1B, 0xB5, 0xFA, 0xEC, 0x51, 0xF6, 0x08, 0x8E, 0xF7 }, ++ { 0x24, 0x76, 0x1E, 0x45, 0xE6, 0x74, 0x39, 0x53, 0x79, 0xFB, 0x17, 0x72, 0x9C, 0x78, 0xCB, 0x93, 0x9E, 0x6F, 0x74, 0xC5, 0xDF, 0xFB, 0x9C, 0x96, 0x1F, 0x49, 0x59, 0x82, 0xC3, 0xED, 0x1F, 0xE3 }, ++ { 0x55, 0xB7, 0x0A, 0x82, 0x13, 0x1E, 0xC9, 0x48, 0x88, 0xD7, 0xAB, 0x54, 0xA7, 0xC5, 0x15, 0x25, 0x5C, 0x39, 0x38, 0xBB, 0x10, 0xBC, 0x78, 0x4D, 0xC9, 0xB6, 0x7F, 0x07, 0x6E, 0x34, 0x1A, 0x73 }, ++ { 0x6A, 0xB9, 0x05, 0x7B, 0x97, 0x7E, 0xBC, 0x3C, 0xA4, 0xD4, 0xCE, 0x74, 0x50, 0x6C, 0x25, 0xCC, 0xCD, 0xC5, 0x66, 0x49, 0x7C, 0x45, 0x0B, 0x54, 0x15, 0xA3, 0x94, 0x86, 0xF8, 0x65, 0x7A, 0x03 }, ++ { 0x24, 0x06, 0x6D, 0xEE, 0xE0, 0xEC, 0xEE, 0x15, 0xA4, 0x5F, 0x0A, 0x32, 0x6D, 0x0F, 0x8D, 0xBC, 0x79, 0x76, 0x1E, 0xBB, 0x93, 0xCF, 0x8C, 0x03, 0x77, 0xAF, 0x44, 0x09, 0x78, 0xFC, 0xF9, 0x94 }, ++ { 0x20, 0x00, 0x0D, 0x3F, 0x66, 0xBA, 0x76, 0x86, 0x0D, 0x5A, 0x95, 0x06, 0x88, 0xB9, 0xAA, 0x0D, 0x76, 0xCF, 0xEA, 0x59, 0xB0, 0x05, 0xD8, 0x59, 0x91, 0x4B, 0x1A, 0x46, 0x65, 0x3A, 0x93, 0x9B }, ++ { 0xB9, 0x2D, 0xAA, 0x79, 0x60, 0x3E, 0x3B, 0xDB, 0xC3, 0xBF, 0xE0, 0xF4, 0x19, 0xE4, 0x09, 0xB2, 0xEA, 0x10, 0xDC, 0x43, 0x5B, 0xEE, 0xFE, 0x29, 0x59, 0xDA, 0x16, 0x89, 0x5D, 0x5D, 0xCA, 0x1C }, ++ { 0xE9, 0x47, 0x94, 0x87, 0x05, 0xB2, 0x06, 0xD5, 0x72, 0xB0, 0xE8, 0xF6, 0x2F, 0x66, 0xA6, 0x55, 0x1C, 0xBD, 0x6B, 0xC3, 0x05, 0xD2, 0x6C, 0xE7, 0x53, 0x9A, 0x12, 0xF9, 0xAA, 0xDF, 0x75, 0x71 }, ++ { 0x3D, 0x67, 0xC1, 0xB3, 0xF9, 0xB2, 0x39, 0x10, 0xE3, 0xD3, 0x5E, 0x6B, 0x0F, 0x2C, 0xCF, 0x44, 0xA0, 0xB5, 0x40, 0xA4, 0x5C, 0x18, 0xBA, 0x3C, 0x36, 0x26, 0x4D, 0xD4, 0x8E, 0x96, 0xAF, 0x6A }, ++ { 0xC7, 0x55, 0x8B, 0xAB, 0xDA, 0x04, 0xBC, 0xCB, 0x76, 0x4D, 0x0B, 0xBF, 0x33, 0x58, 0x42, 0x51, 0x41, 0x90, 0x2D, 0x22, 0x39, 0x1D, 0x9F, 0x8C, 0x59, 0x15, 0x9F, 0xEC, 0x9E, 0x49, 0xB1, 0x51 }, ++ { 0x0B, 0x73, 0x2B, 0xB0, 0x35, 0x67, 0x5A, 0x50, 0xFF, 0x58, 0xF2, 0xC2, 0x42, 0xE4, 0x71, 0x0A, 0xEC, 0xE6, 0x46, 0x70, 0x07, 0x9C, 0x13, 0x04, 0x4C, 0x79, 0xC9, 0xB7, 0x49, 0x1F, 0x70, 0x00 }, ++ { 0xD1, 0x20, 0xB5, 0xEF, 0x6D, 0x57, 0xEB, 0xF0, 0x6E, 0xAF, 0x96, 0xBC, 0x93, 0x3C, 0x96, 0x7B, 0x16, 0xCB, 0xE6, 0xE2, 0xBF, 0x00, 0x74, 0x1C, 0x30, 0xAA, 0x1C, 0x54, 0xBA, 0x64, 0x80, 0x1F }, ++ { 0x58, 0xD2, 0x12, 0xAD, 0x6F, 0x58, 0xAE, 0xF0, 0xF8, 0x01, 0x16, 0xB4, 0x41, 0xE5, 0x7F, 0x61, 0x95, 0xBF, 0xEF, 0x26, 0xB6, 0x14, 0x63, 0xED, 0xEC, 0x11, 0x83, 0xCD, 0xB0, 0x4F, 0xE7, 0x6D }, ++ { 0xB8, 0x83, 0x6F, 0x51, 0xD1, 0xE2, 0x9B, 0xDF, 0xDB, 0xA3, 0x25, 0x56, 0x53, 0x60, 0x26, 0x8B, 0x8F, 0xAD, 0x62, 0x74, 0x73, 0xED, 0xEC, 0xEF, 0x7E, 0xAE, 0xFE, 0xE8, 0x37, 0xC7, 0x40, 0x03 }, ++ { 0xC5, 0x47, 0xA3, 0xC1, 0x24, 0xAE, 0x56, 0x85, 0xFF, 0xA7, 0xB8, 0xED, 0xAF, 0x96, 0xEC, 0x86, 0xF8, 0xB2, 0xD0, 0xD5, 0x0C, 0xEE, 0x8B, 0xE3, 0xB1, 0xF0, 0xC7, 0x67, 0x63, 0x06, 0x9D, 0x9C }, ++ { 0x5D, 0x16, 0x8B, 0x76, 0x9A, 0x2F, 0x67, 0x85, 0x3D, 0x62, 0x95, 0xF7, 0x56, 0x8B, 0xE4, 0x0B, 0xB7, 0xA1, 0x6B, 0x8D, 0x65, 0xBA, 0x87, 0x63, 0x5D, 0x19, 0x78, 0xD2, 0xAB, 0x11, 0xBA, 0x2A }, ++ { 0xA2, 0xF6, 0x75, 0xDC, 0x73, 0x02, 0x63, 0x8C, 0xB6, 0x02, 0x01, 0x06, 0x4C, 0xA5, 0x50, 0x77, 0x71, 0x4D, 0x71, 0xFE, 0x09, 0x6A, 0x31, 0x5F, 0x2F, 0xE7, 0x40, 0x12, 0x77, 0xCA, 0xA5, 0xAF }, ++ { 0xC8, 0xAA, 0xB5, 0xCD, 0x01, 0x60, 0xAE, 0x78, 0xCD, 0x2E, 0x8A, 0xC5, 0xFB, 0x0E, 0x09, 0x3C, 0xDB, 0x5C, 0x4B, 0x60, 0x52, 0xA0, 0xA9, 0x7B, 0xB0, 0x42, 0x16, 0x82, 0x6F, 0xA7, 0xA4, 0x37 }, ++ { 0xFF, 0x68, 0xCA, 0x40, 0x35, 0xBF, 0xEB, 0x43, 0xFB, 0xF1, 0x45, 0xFD, 0xDD, 0x5E, 0x43, 0xF1, 0xCE, 0xA5, 0x4F, 0x11, 0xF7, 0xBE, 0xE1, 0x30, 0x58, 0xF0, 0x27, 0x32, 0x9A, 0x4A, 0x5F, 0xA4 }, ++ { 0x1D, 0x4E, 0x54, 0x87, 0xAE, 0x3C, 0x74, 0x0F, 0x2B, 0xA6, 0xE5, 0x41, 0xAC, 0x91, 0xBC, 0x2B, 0xFC, 0xD2, 0x99, 0x9C, 0x51, 0x8D, 0x80, 0x7B, 0x42, 0x67, 0x48, 0x80, 0x3A, 0x35, 0x0F, 0xD4 }, ++ { 0x6D, 0x24, 0x4E, 0x1A, 0x06, 0xCE, 0x4E, 0xF5, 0x78, 0xDD, 0x0F, 0x63, 0xAF, 0xF0, 0x93, 0x67, 0x06, 0x73, 0x51, 0x19, 0xCA, 0x9C, 0x8D, 0x22, 0xD8, 0x6C, 0x80, 0x14, 0x14, 0xAB, 0x97, 0x41 }, ++ { 0xDE, 0xCF, 0x73, 0x29, 0xDB, 0xCC, 0x82, 0x7B, 0x8F, 0xC5, 0x24, 0xC9, 0x43, 0x1E, 0x89, 0x98, 0x02, 0x9E, 0xCE, 0x12, 0xCE, 0x93, 0xB7, 0xB2, 0xF3, 0xE7, 0x69, 0xA9, 0x41, 0xFB, 0x8C, 0xEA }, ++ { 0x2F, 0xAF, 0xCC, 0x0F, 0x2E, 0x63, 0xCB, 0xD0, 0x77, 0x55, 0xBE, 0x7B, 0x75, 0xEC, 0xEA, 0x0A, 0xDF, 0xF9, 0xAA, 0x5E, 0xDE, 0x2A, 0x52, 0xFD, 0xAB, 0x4D, 0xFD, 0x03, 0x74, 0xCD, 0x48, 0x3F }, ++ { 0xAA, 0x85, 0x01, 0x0D, 0xD4, 0x6A, 0x54, 0x6B, 0x53, 0x5E, 0xF4, 0xCF, 0x5F, 0x07, 0xD6, 0x51, 0x61, 0xE8, 0x98, 0x28, 0xF3, 0xA7, 0x7D, 0xB7, 0xB9, 0xB5, 0x6F, 0x0D, 0xF5, 0x9A, 0xAE, 0x45 }, ++ { 0x07, 0xE8, 0xE1, 0xEE, 0x73, 0x2C, 0xB0, 0xD3, 0x56, 0xC9, 0xC0, 0xD1, 0x06, 0x9C, 0x89, 0xD1, 0x7A, 0xDF, 0x6A, 0x9A, 0x33, 0x4F, 0x74, 0x5E, 0xC7, 0x86, 0x73, 0x32, 0x54, 0x8C, 0xA8, 0xE9 }, ++ { 0x0E, 0x01, 0xE8, 0x1C, 0xAD, 0xA8, 0x16, 0x2B, 0xFD, 0x5F, 0x8A, 0x8C, 0x81, 0x8A, 0x6C, 0x69, 0xFE, 0xDF, 0x02, 0xCE, 0xB5, 0x20, 0x85, 0x23, 0xCB, 0xE5, 0x31, 0x3B, 0x89, 0xCA, 0x10, 0x53 }, ++ { 0x6B, 0xB6, 0xC6, 0x47, 0x26, 0x55, 0x08, 0x43, 0x99, 0x85, 0x2E, 0x00, 0x24, 0x9F, 0x8C, 0xB2, 0x47, 0x89, 0x6D, 0x39, 0x2B, 0x02, 0xD7, 0x3B, 0x7F, 0x0D, 0xD8, 0x18, 0xE1, 0xE2, 0x9B, 0x07 }, ++ { 0x42, 0xD4, 0x63, 0x6E, 0x20, 0x60, 0xF0, 0x8F, 0x41, 0xC8, 0x82, 0xE7, 0x6B, 0x39, 0x6B, 0x11, 0x2E, 0xF6, 0x27, 0xCC, 0x24, 0xC4, 0x3D, 0xD5, 0xF8, 0x3A, 0x1D, 0x1A, 0x7E, 0xAD, 0x71, 0x1A }, ++ { 0x48, 0x58, 0xC9, 0xA1, 0x88, 0xB0, 0x23, 0x4F, 0xB9, 0xA8, 0xD4, 0x7D, 0x0B, 0x41, 0x33, 0x65, 0x0A, 0x03, 0x0B, 0xD0, 0x61, 0x1B, 0x87, 0xC3, 0x89, 0x2E, 0x94, 0x95, 0x1F, 0x8D, 0xF8, 0x52 }, ++ { 0x3F, 0xAB, 0x3E, 0x36, 0x98, 0x8D, 0x44, 0x5A, 0x51, 0xC8, 0x78, 0x3E, 0x53, 0x1B, 0xE3, 0xA0, 0x2B, 0xE4, 0x0C, 0xD0, 0x47, 0x96, 0xCF, 0xB6, 0x1D, 0x40, 0x34, 0x74, 0x42, 0xD3, 0xF7, 0x94 }, ++ { 0xEB, 0xAB, 0xC4, 0x96, 0x36, 0xBD, 0x43, 0x3D, 0x2E, 0xC8, 0xF0, 0xE5, 0x18, 0x73, 0x2E, 0xF8, 0xFA, 0x21, 0xD4, 0xD0, 0x71, 0xCC, 0x3B, 0xC4, 0x6C, 0xD7, 0x9F, 0xA3, 0x8A, 0x28, 0xB8, 0x10 }, ++ { 0xA1, 0xD0, 0x34, 0x35, 0x23, 0xB8, 0x93, 0xFC, 0xA8, 0x4F, 0x47, 0xFE, 0xB4, 0xA6, 0x4D, 0x35, 0x0A, 0x17, 0xD8, 0xEE, 0xF5, 0x49, 0x7E, 0xCE, 0x69, 0x7D, 0x02, 0xD7, 0x91, 0x78, 0xB5, 0x91 }, ++ { 0x26, 0x2E, 0xBF, 0xD9, 0x13, 0x0B, 0x7D, 0x28, 0x76, 0x0D, 0x08, 0xEF, 0x8B, 0xFD, 0x3B, 0x86, 0xCD, 0xD3, 0xB2, 0x11, 0x3D, 0x2C, 0xAE, 0xF7, 0xEA, 0x95, 0x1A, 0x30, 0x3D, 0xFA, 0x38, 0x46 }, ++ { 0xF7, 0x61, 0x58, 0xED, 0xD5, 0x0A, 0x15, 0x4F, 0xA7, 0x82, 0x03, 0xED, 0x23, 0x62, 0x93, 0x2F, 0xCB, 0x82, 0x53, 0xAA, 0xE3, 0x78, 0x90, 0x3E, 0xDE, 0xD1, 0xE0, 0x3F, 0x70, 0x21, 0xA2, 0x57 }, ++ { 0x26, 0x17, 0x8E, 0x95, 0x0A, 0xC7, 0x22, 0xF6, 0x7A, 0xE5, 0x6E, 0x57, 0x1B, 0x28, 0x4C, 0x02, 0x07, 0x68, 0x4A, 0x63, 0x34, 0xA1, 0x77, 0x48, 0xA9, 0x4D, 0x26, 0x0B, 0xC5, 0xF5, 0x52, 0x74 }, ++ { 0xC3, 0x78, 0xD1, 0xE4, 0x93, 0xB4, 0x0E, 0xF1, 0x1F, 0xE6, 0xA1, 0x5D, 0x9C, 0x27, 0x37, 0xA3, 0x78, 0x09, 0x63, 0x4C, 0x5A, 0xBA, 0xD5, 0xB3, 0x3D, 0x7E, 0x39, 0x3B, 0x4A, 0xE0, 0x5D, 0x03 }, ++ { 0x98, 0x4B, 0xD8, 0x37, 0x91, 0x01, 0xBE, 0x8F, 0xD8, 0x06, 0x12, 0xD8, 0xEA, 0x29, 0x59, 0xA7, 0x86, 0x5E, 0xC9, 0x71, 0x85, 0x23, 0x55, 0x01, 0x07, 0xAE, 0x39, 0x38, 0xDF, 0x32, 0x01, 0x1B }, ++ { 0xC6, 0xF2, 0x5A, 0x81, 0x2A, 0x14, 0x48, 0x58, 0xAC, 0x5C, 0xED, 0x37, 0xA9, 0x3A, 0x9F, 0x47, 0x59, 0xBA, 0x0B, 0x1C, 0x0F, 0xDC, 0x43, 0x1D, 0xCE, 0x35, 0xF9, 0xEC, 0x1F, 0x1F, 0x4A, 0x99 }, ++ { 0x92, 0x4C, 0x75, 0xC9, 0x44, 0x24, 0xFF, 0x75, 0xE7, 0x4B, 0x8B, 0x4E, 0x94, 0x35, 0x89, 0x58, 0xB0, 0x27, 0xB1, 0x71, 0xDF, 0x5E, 0x57, 0x89, 0x9A, 0xD0, 0xD4, 0xDA, 0xC3, 0x73, 0x53, 0xB6 }, ++ { 0x0A, 0xF3, 0x58, 0x92, 0xA6, 0x3F, 0x45, 0x93, 0x1F, 0x68, 0x46, 0xED, 0x19, 0x03, 0x61, 0xCD, 0x07, 0x30, 0x89, 0xE0, 0x77, 0x16, 0x57, 0x14, 0xB5, 0x0B, 0x81, 0xA2, 0xE3, 0xDD, 0x9B, 0xA1 }, ++ { 0xCC, 0x80, 0xCE, 0xFB, 0x26, 0xC3, 0xB2, 0xB0, 0xDA, 0xEF, 0x23, 0x3E, 0x60, 0x6D, 0x5F, 0xFC, 0x80, 0xFA, 0x17, 0x42, 0x7D, 0x18, 0xE3, 0x04, 0x89, 0x67, 0x3E, 0x06, 0xEF, 0x4B, 0x87, 0xF7 }, ++ { 0xC2, 0xF8, 0xC8, 0x11, 0x74, 0x47, 0xF3, 0x97, 0x8B, 0x08, 0x18, 0xDC, 0xF6, 0xF7, 0x01, 0x16, 0xAC, 0x56, 0xFD, 0x18, 0x4D, 0xD1, 0x27, 0x84, 0x94, 0xE1, 0x03, 0xFC, 0x6D, 0x74, 0xA8, 0x87 }, ++ { 0xBD, 0xEC, 0xF6, 0xBF, 0xC1, 0xBA, 0x0D, 0xF6, 0xE8, 0x62, 0xC8, 0x31, 0x99, 0x22, 0x07, 0x79, 0x6A, 0xCC, 0x79, 0x79, 0x68, 0x35, 0x88, 0x28, 0xC0, 0x6E, 0x7A, 0x51, 0xE0, 0x90, 0x09, 0x8F }, ++ { 0x24, 0xD1, 0xA2, 0x6E, 0x3D, 0xAB, 0x02, 0xFE, 0x45, 0x72, 0xD2, 0xAA, 0x7D, 0xBD, 0x3E, 0xC3, 0x0F, 0x06, 0x93, 0xDB, 0x26, 0xF2, 0x73, 0xD0, 0xAB, 0x2C, 0xB0, 0xC1, 0x3B, 0x5E, 0x64, 0x51 }, ++ { 0xEC, 0x56, 0xF5, 0x8B, 0x09, 0x29, 0x9A, 0x30, 0x0B, 0x14, 0x05, 0x65, 0xD7, 0xD3, 0xE6, 0x87, 0x82, 0xB6, 0xE2, 0xFB, 0xEB, 0x4B, 0x7E, 0xA9, 0x7A, 0xC0, 0x57, 0x98, 0x90, 0x61, 0xDD, 0x3F }, ++ { 0x11, 0xA4, 0x37, 0xC1, 0xAB, 0xA3, 0xC1, 0x19, 0xDD, 0xFA, 0xB3, 0x1B, 0x3E, 0x8C, 0x84, 0x1D, 0xEE, 0xEB, 0x91, 0x3E, 0xF5, 0x7F, 0x7E, 0x48, 0xF2, 0xC9, 0xCF, 0x5A, 0x28, 0xFA, 0x42, 0xBC }, ++ { 0x53, 0xC7, 0xE6, 0x11, 0x4B, 0x85, 0x0A, 0x2C, 0xB4, 0x96, 0xC9, 0xB3, 0xC6, 0x9A, 0x62, 0x3E, 0xAE, 0xA2, 0xCB, 0x1D, 0x33, 0xDD, 0x81, 0x7E, 0x47, 0x65, 0xED, 0xAA, 0x68, 0x23, 0xC2, 0x28 }, ++ { 0x15, 0x4C, 0x3E, 0x96, 0xFE, 0xE5, 0xDB, 0x14, 0xF8, 0x77, 0x3E, 0x18, 0xAF, 0x14, 0x85, 0x79, 0x13, 0x50, 0x9D, 0xA9, 0x99, 0xB4, 0x6C, 0xDD, 0x3D, 0x4C, 0x16, 0x97, 0x60, 0xC8, 0x3A, 0xD2 }, ++ { 0x40, 0xB9, 0x91, 0x6F, 0x09, 0x3E, 0x02, 0x7A, 0x87, 0x86, 0x64, 0x18, 0x18, 0x92, 0x06, 0x20, 0x47, 0x2F, 0xBC, 0xF6, 0x8F, 0x70, 0x1D, 0x1B, 0x68, 0x06, 0x32, 0xE6, 0x99, 0x6B, 0xDE, 0xD3 }, ++ { 0x24, 0xC4, 0xCB, 0xBA, 0x07, 0x11, 0x98, 0x31, 0xA7, 0x26, 0xB0, 0x53, 0x05, 0xD9, 0x6D, 0xA0, 0x2F, 0xF8, 0xB1, 0x48, 0xF0, 0xDA, 0x44, 0x0F, 0xE2, 0x33, 0xBC, 0xAA, 0x32, 0xC7, 0x2F, 0x6F }, ++ { 0x5D, 0x20, 0x15, 0x10, 0x25, 0x00, 0x20, 0xB7, 0x83, 0x68, 0x96, 0x88, 0xAB, 0xBF, 0x8E, 0xCF, 0x25, 0x94, 0xA9, 0x6A, 0x08, 0xF2, 0xBF, 0xEC, 0x6C, 0xE0, 0x57, 0x44, 0x65, 0xDD, 0xED, 0x71 }, ++ { 0x04, 0x3B, 0x97, 0xE3, 0x36, 0xEE, 0x6F, 0xDB, 0xBE, 0x2B, 0x50, 0xF2, 0x2A, 0xF8, 0x32, 0x75, 0xA4, 0x08, 0x48, 0x05, 0xD2, 0xD5, 0x64, 0x59, 0x62, 0x45, 0x4B, 0x6C, 0x9B, 0x80, 0x53, 0xA0 }, ++ { 0x56, 0x48, 0x35, 0xCB, 0xAE, 0xA7, 0x74, 0x94, 0x85, 0x68, 0xBE, 0x36, 0xCF, 0x52, 0xFC, 0xDD, 0x83, 0x93, 0x4E, 0xB0, 0xA2, 0x75, 0x12, 0xDB, 0xE3, 0xE2, 0xDB, 0x47, 0xB9, 0xE6, 0x63, 0x5A }, ++ { 0xF2, 0x1C, 0x33, 0xF4, 0x7B, 0xDE, 0x40, 0xA2, 0xA1, 0x01, 0xC9, 0xCD, 0xE8, 0x02, 0x7A, 0xAF, 0x61, 0xA3, 0x13, 0x7D, 0xE2, 0x42, 0x2B, 0x30, 0x03, 0x5A, 0x04, 0xC2, 0x70, 0x89, 0x41, 0x83 }, ++ { 0x9D, 0xB0, 0xEF, 0x74, 0xE6, 0x6C, 0xBB, 0x84, 0x2E, 0xB0, 0xE0, 0x73, 0x43, 0xA0, 0x3C, 0x5C, 0x56, 0x7E, 0x37, 0x2B, 0x3F, 0x23, 0xB9, 0x43, 0xC7, 0x88, 0xA4, 0xF2, 0x50, 0xF6, 0x78, 0x91 }, ++ { 0xAB, 0x8D, 0x08, 0x65, 0x5F, 0xF1, 0xD3, 0xFE, 0x87, 0x58, 0xD5, 0x62, 0x23, 0x5F, 0xD2, 0x3E, 0x7C, 0xF9, 0xDC, 0xAA, 0xD6, 0x58, 0x87, 0x2A, 0x49, 0xE5, 0xD3, 0x18, 0x3B, 0x6C, 0xCE, 0xBD }, ++ { 0x6F, 0x27, 0xF7, 0x7E, 0x7B, 0xCF, 0x46, 0xA1, 0xE9, 0x63, 0xAD, 0xE0, 0x30, 0x97, 0x33, 0x54, 0x30, 0x31, 0xDC, 0xCD, 0xD4, 0x7C, 0xAA, 0xC1, 0x74, 0xD7, 0xD2, 0x7C, 0xE8, 0x07, 0x7E, 0x8B }, ++ { 0xE3, 0xCD, 0x54, 0xDA, 0x7E, 0x44, 0x4C, 0xAA, 0x62, 0x07, 0x56, 0x95, 0x25, 0xA6, 0x70, 0xEB, 0xAE, 0x12, 0x78, 0xDE, 0x4E, 0x3F, 0xE2, 0x68, 0x4B, 0x3E, 0x33, 0xF5, 0xEF, 0x90, 0xCC, 0x1B }, ++ { 0xB2, 0xC3, 0xE3, 0x3A, 0x51, 0xD2, 0x2C, 0x4C, 0x08, 0xFC, 0x09, 0x89, 0xC8, 0x73, 0xC9, 0xCC, 0x41, 0x50, 0x57, 0x9B, 0x1E, 0x61, 0x63, 0xFA, 0x69, 0x4A, 0xD5, 0x1D, 0x53, 0xD7, 0x12, 0xDC }, ++ { 0xBE, 0x7F, 0xDA, 0x98, 0x3E, 0x13, 0x18, 0x9B, 0x4C, 0x77, 0xE0, 0xA8, 0x09, 0x20, 0xB6, 0xE0, 0xE0, 0xEA, 0x80, 0xC3, 0xB8, 0x4D, 0xBE, 0x7E, 0x71, 0x17, 0xD2, 0x53, 0xF4, 0x81, 0x12, 0xF4 }, ++ { 0xB6, 0x00, 0x8C, 0x28, 0xFA, 0xE0, 0x8A, 0xA4, 0x27, 0xE5, 0xBD, 0x3A, 0xAD, 0x36, 0xF1, 0x00, 0x21, 0xF1, 0x6C, 0x77, 0xCF, 0xEA, 0xBE, 0xD0, 0x7F, 0x97, 0xCC, 0x7D, 0xC1, 0xF1, 0x28, 0x4A }, ++ { 0x6E, 0x4E, 0x67, 0x60, 0xC5, 0x38, 0xF2, 0xE9, 0x7B, 0x3A, 0xDB, 0xFB, 0xBC, 0xDE, 0x57, 0xF8, 0x96, 0x6B, 0x7E, 0xA8, 0xFC, 0xB5, 0xBF, 0x7E, 0xFE, 0xC9, 0x13, 0xFD, 0x2A, 0x2B, 0x0C, 0x55 }, ++ { 0x4A, 0xE5, 0x1F, 0xD1, 0x83, 0x4A, 0xA5, 0xBD, 0x9A, 0x6F, 0x7E, 0xC3, 0x9F, 0xC6, 0x63, 0x33, 0x8D, 0xC5, 0xD2, 0xE2, 0x07, 0x61, 0x56, 0x6D, 0x90, 0xCC, 0x68, 0xB1, 0xCB, 0x87, 0x5E, 0xD8 }, ++ { 0xB6, 0x73, 0xAA, 0xD7, 0x5A, 0xB1, 0xFD, 0xB5, 0x40, 0x1A, 0xBF, 0xA1, 0xBF, 0x89, 0xF3, 0xAD, 0xD2, 0xEB, 0xC4, 0x68, 0xDF, 0x36, 0x24, 0xA4, 0x78, 0xF4, 0xFE, 0x85, 0x9D, 0x8D, 0x55, 0xE2 }, ++ { 0x13, 0xC9, 0x47, 0x1A, 0x98, 0x55, 0x91, 0x35, 0x39, 0x83, 0x66, 0x60, 0x39, 0x8D, 0xA0, 0xF3, 0xF9, 0x9A, 0xDA, 0x08, 0x47, 0x9C, 0x69, 0xD1, 0xB7, 0xFC, 0xAA, 0x34, 0x61, 0xDD, 0x7E, 0x59 }, ++ { 0x2C, 0x11, 0xF4, 0xA7, 0xF9, 0x9A, 0x1D, 0x23, 0xA5, 0x8B, 0xB6, 0x36, 0x35, 0x0F, 0xE8, 0x49, 0xF2, 0x9C, 0xBA, 0xC1, 0xB2, 0xA1, 0x11, 0x2D, 0x9F, 0x1E, 0xD5, 0xBC, 0x5B, 0x31, 0x3C, 0xCD }, ++ { 0xC7, 0xD3, 0xC0, 0x70, 0x6B, 0x11, 0xAE, 0x74, 0x1C, 0x05, 0xA1, 0xEF, 0x15, 0x0D, 0xD6, 0x5B, 0x54, 0x94, 0xD6, 0xD5, 0x4C, 0x9A, 0x86, 0xE2, 0x61, 0x78, 0x54, 0xE6, 0xAE, 0xEE, 0xBB, 0xD9 }, ++ { 0x19, 0x4E, 0x10, 0xC9, 0x38, 0x93, 0xAF, 0xA0, 0x64, 0xC3, 0xAC, 0x04, 0xC0, 0xDD, 0x80, 0x8D, 0x79, 0x1C, 0x3D, 0x4B, 0x75, 0x56, 0xE8, 0x9D, 0x8D, 0x9C, 0xB2, 0x25, 0xC4, 0xB3, 0x33, 0x39 }, ++ { 0x6F, 0xC4, 0x98, 0x8B, 0x8F, 0x78, 0x54, 0x6B, 0x16, 0x88, 0x99, 0x18, 0x45, 0x90, 0x8F, 0x13, 0x4B, 0x6A, 0x48, 0x2E, 0x69, 0x94, 0xB3, 0xD4, 0x83, 0x17, 0xBF, 0x08, 0xDB, 0x29, 0x21, 0x85 }, ++ { 0x56, 0x65, 0xBE, 0xB8, 0xB0, 0x95, 0x55, 0x25, 0x81, 0x3B, 0x59, 0x81, 0xCD, 0x14, 0x2E, 0xD4, 0xD0, 0x3F, 0xBA, 0x38, 0xA6, 0xF3, 0xE5, 0xAD, 0x26, 0x8E, 0x0C, 0xC2, 0x70, 0xD1, 0xCD, 0x11 }, ++ { 0xB8, 0x83, 0xD6, 0x8F, 0x5F, 0xE5, 0x19, 0x36, 0x43, 0x1B, 0xA4, 0x25, 0x67, 0x38, 0x05, 0x3B, 0x1D, 0x04, 0x26, 0xD4, 0xCB, 0x64, 0xB1, 0x6E, 0x83, 0xBA, 0xDC, 0x5E, 0x9F, 0xBE, 0x3B, 0x81 }, ++ { 0x53, 0xE7, 0xB2, 0x7E, 0xA5, 0x9C, 0x2F, 0x6D, 0xBB, 0x50, 0x76, 0x9E, 0x43, 0x55, 0x4D, 0xF3, 0x5A, 0xF8, 0x9F, 0x48, 0x22, 0xD0, 0x46, 0x6B, 0x00, 0x7D, 0xD6, 0xF6, 0xDE, 0xAF, 0xFF, 0x02 }, ++ { 0x1F, 0x1A, 0x02, 0x29, 0xD4, 0x64, 0x0F, 0x01, 0x90, 0x15, 0x88, 0xD9, 0xDE, 0xC2, 0x2D, 0x13, 0xFC, 0x3E, 0xB3, 0x4A, 0x61, 0xB3, 0x29, 0x38, 0xEF, 0xBF, 0x53, 0x34, 0xB2, 0x80, 0x0A, 0xFA }, ++ { 0xC2, 0xB4, 0x05, 0xAF, 0xA0, 0xFA, 0x66, 0x68, 0x85, 0x2A, 0xEE, 0x4D, 0x88, 0x04, 0x08, 0x53, 0xFA, 0xB8, 0x00, 0xE7, 0x2B, 0x57, 0x58, 0x14, 0x18, 0xE5, 0x50, 0x6F, 0x21, 0x4C, 0x7D, 0x1F }, ++ { 0xC0, 0x8A, 0xA1, 0xC2, 0x86, 0xD7, 0x09, 0xFD, 0xC7, 0x47, 0x37, 0x44, 0x97, 0x71, 0x88, 0xC8, 0x95, 0xBA, 0x01, 0x10, 0x14, 0x24, 0x7E, 0x4E, 0xFA, 0x8D, 0x07, 0xE7, 0x8F, 0xEC, 0x69, 0x5C }, ++ { 0xF0, 0x3F, 0x57, 0x89, 0xD3, 0x33, 0x6B, 0x80, 0xD0, 0x02, 0xD5, 0x9F, 0xDF, 0x91, 0x8B, 0xDB, 0x77, 0x5B, 0x00, 0x95, 0x6E, 0xD5, 0x52, 0x8E, 0x86, 0xAA, 0x99, 0x4A, 0xCB, 0x38, 0xFE, 0x2D } ++}; ++ ++static const u8 blake2s_keyed_testvecs[][BLAKE2S_OUTBYTES] = { ++ { 0x48, 0xA8, 0x99, 0x7D, 0xA4, 0x07, 0x87, 0x6B, 0x3D, 0x79, 0xC0, 0xD9, 0x23, 0x25, 0xAD, 0x3B, 0x89, 0xCB, 0xB7, 0x54, 0xD8, 0x6A, 0xB7, 0x1A, 0xEE, 0x04, 0x7A, 0xD3, 0x45, 0xFD, 0x2C, 0x49 }, ++ { 0x40, 0xD1, 0x5F, 0xEE, 0x7C, 0x32, 0x88, 0x30, 0x16, 0x6A, 0xC3, 0xF9, 0x18, 0x65, 0x0F, 0x80, 0x7E, 0x7E, 0x01, 0xE1, 0x77, 0x25, 0x8C, 0xDC, 0x0A, 0x39, 0xB1, 0x1F, 0x59, 0x80, 0x66, 0xF1 }, ++ { 0x6B, 0xB7, 0x13, 0x00, 0x64, 0x4C, 0xD3, 0x99, 0x1B, 0x26, 0xCC, 0xD4, 0xD2, 0x74, 0xAC, 0xD1, 0xAD, 0xEA, 0xB8, 0xB1, 0xD7, 0x91, 0x45, 0x46, 0xC1, 0x19, 0x8B, 0xBE, 0x9F, 0xC9, 0xD8, 0x03 }, ++ { 0x1D, 0x22, 0x0D, 0xBE, 0x2E, 0xE1, 0x34, 0x66, 0x1F, 0xDF, 0x6D, 0x9E, 0x74, 0xB4, 0x17, 0x04, 0x71, 0x05, 0x56, 0xF2, 0xF6, 0xE5, 0xA0, 0x91, 0xB2, 0x27, 0x69, 0x74, 0x45, 0xDB, 0xEA, 0x6B }, ++ { 0xF6, 0xC3, 0xFB, 0xAD, 0xB4, 0xCC, 0x68, 0x7A, 0x00, 0x64, 0xA5, 0xBE, 0x6E, 0x79, 0x1B, 0xEC, 0x63, 0xB8, 0x68, 0xAD, 0x62, 0xFB, 0xA6, 0x1B, 0x37, 0x57, 0xEF, 0x9C, 0xA5, 0x2E, 0x05, 0xB2 }, ++ { 0x49, 0xC1, 0xF2, 0x11, 0x88, 0xDF, 0xD7, 0x69, 0xAE, 0xA0, 0xE9, 0x11, 0xDD, 0x6B, 0x41, 0xF1, 0x4D, 0xAB, 0x10, 0x9D, 0x2B, 0x85, 0x97, 0x7A, 0xA3, 0x08, 0x8B, 0x5C, 0x70, 0x7E, 0x85, 0x98 }, ++ { 0xFD, 0xD8, 0x99, 0x3D, 0xCD, 0x43, 0xF6, 0x96, 0xD4, 0x4F, 0x3C, 0xEA, 0x0F, 0xF3, 0x53, 0x45, 0x23, 0x4E, 0xC8, 0xEE, 0x08, 0x3E, 0xB3, 0xCA, 0xDA, 0x01, 0x7C, 0x7F, 0x78, 0xC1, 0x71, 0x43 }, ++ { 0xE6, 0xC8, 0x12, 0x56, 0x37, 0x43, 0x8D, 0x09, 0x05, 0xB7, 0x49, 0xF4, 0x65, 0x60, 0xAC, 0x89, 0xFD, 0x47, 0x1C, 0xF8, 0x69, 0x2E, 0x28, 0xFA, 0xB9, 0x82, 0xF7, 0x3F, 0x01, 0x9B, 0x83, 0xA9 }, ++ { 0x19, 0xFC, 0x8C, 0xA6, 0x97, 0x9D, 0x60, 0xE6, 0xED, 0xD3, 0xB4, 0x54, 0x1E, 0x2F, 0x96, 0x7C, 0xED, 0x74, 0x0D, 0xF6, 0xEC, 0x1E, 0xAE, 0xBB, 0xFE, 0x81, 0x38, 0x32, 0xE9, 0x6B, 0x29, 0x74 }, ++ { 0xA6, 0xAD, 0x77, 0x7C, 0xE8, 0x81, 0xB5, 0x2B, 0xB5, 0xA4, 0x42, 0x1A, 0xB6, 0xCD, 0xD2, 0xDF, 0xBA, 0x13, 0xE9, 0x63, 0x65, 0x2D, 0x4D, 0x6D, 0x12, 0x2A, 0xEE, 0x46, 0x54, 0x8C, 0x14, 0xA7 }, ++ { 0xF5, 0xC4, 0xB2, 0xBA, 0x1A, 0x00, 0x78, 0x1B, 0x13, 0xAB, 0xA0, 0x42, 0x52, 0x42, 0xC6, 0x9C, 0xB1, 0x55, 0x2F, 0x3F, 0x71, 0xA9, 0xA3, 0xBB, 0x22, 0xB4, 0xA6, 0xB4, 0x27, 0x7B, 0x46, 0xDD }, ++ { 0xE3, 0x3C, 0x4C, 0x9B, 0xD0, 0xCC, 0x7E, 0x45, 0xC8, 0x0E, 0x65, 0xC7, 0x7F, 0xA5, 0x99, 0x7F, 0xEC, 0x70, 0x02, 0x73, 0x85, 0x41, 0x50, 0x9E, 0x68, 0xA9, 0x42, 0x38, 0x91, 0xE8, 0x22, 0xA3 }, ++ { 0xFB, 0xA1, 0x61, 0x69, 0xB2, 0xC3, 0xEE, 0x10, 0x5B, 0xE6, 0xE1, 0xE6, 0x50, 0xE5, 0xCB, 0xF4, 0x07, 0x46, 0xB6, 0x75, 0x3D, 0x03, 0x6A, 0xB5, 0x51, 0x79, 0x01, 0x4A, 0xD7, 0xEF, 0x66, 0x51 }, ++ { 0xF5, 0xC4, 0xBE, 0xC6, 0xD6, 0x2F, 0xC6, 0x08, 0xBF, 0x41, 0xCC, 0x11, 0x5F, 0x16, 0xD6, 0x1C, 0x7E, 0xFD, 0x3F, 0xF6, 0xC6, 0x56, 0x92, 0xBB, 0xE0, 0xAF, 0xFF, 0xB1, 0xFE, 0xDE, 0x74, 0x75 }, ++ { 0xA4, 0x86, 0x2E, 0x76, 0xDB, 0x84, 0x7F, 0x05, 0xBA, 0x17, 0xED, 0xE5, 0xDA, 0x4E, 0x7F, 0x91, 0xB5, 0x92, 0x5C, 0xF1, 0xAD, 0x4B, 0xA1, 0x27, 0x32, 0xC3, 0x99, 0x57, 0x42, 0xA5, 0xCD, 0x6E }, ++ { 0x65, 0xF4, 0xB8, 0x60, 0xCD, 0x15, 0xB3, 0x8E, 0xF8, 0x14, 0xA1, 0xA8, 0x04, 0x31, 0x4A, 0x55, 0xBE, 0x95, 0x3C, 0xAA, 0x65, 0xFD, 0x75, 0x8A, 0xD9, 0x89, 0xFF, 0x34, 0xA4, 0x1C, 0x1E, 0xEA }, ++ { 0x19, 0xBA, 0x23, 0x4F, 0x0A, 0x4F, 0x38, 0x63, 0x7D, 0x18, 0x39, 0xF9, 0xD9, 0xF7, 0x6A, 0xD9, 0x1C, 0x85, 0x22, 0x30, 0x71, 0x43, 0xC9, 0x7D, 0x5F, 0x93, 0xF6, 0x92, 0x74, 0xCE, 0xC9, 0xA7 }, ++ { 0x1A, 0x67, 0x18, 0x6C, 0xA4, 0xA5, 0xCB, 0x8E, 0x65, 0xFC, 0xA0, 0xE2, 0xEC, 0xBC, 0x5D, 0xDC, 0x14, 0xAE, 0x38, 0x1B, 0xB8, 0xBF, 0xFE, 0xB9, 0xE0, 0xA1, 0x03, 0x44, 0x9E, 0x3E, 0xF0, 0x3C }, ++ { 0xAF, 0xBE, 0xA3, 0x17, 0xB5, 0xA2, 0xE8, 0x9C, 0x0B, 0xD9, 0x0C, 0xCF, 0x5D, 0x7F, 0xD0, 0xED, 0x57, 0xFE, 0x58, 0x5E, 0x4B, 0xE3, 0x27, 0x1B, 0x0A, 0x6B, 0xF0, 0xF5, 0x78, 0x6B, 0x0F, 0x26 }, ++ { 0xF1, 0xB0, 0x15, 0x58, 0xCE, 0x54, 0x12, 0x62, 0xF5, 0xEC, 0x34, 0x29, 0x9D, 0x6F, 0xB4, 0x09, 0x00, 0x09, 0xE3, 0x43, 0x4B, 0xE2, 0xF4, 0x91, 0x05, 0xCF, 0x46, 0xAF, 0x4D, 0x2D, 0x41, 0x24 }, ++ { 0x13, 0xA0, 0xA0, 0xC8, 0x63, 0x35, 0x63, 0x5E, 0xAA, 0x74, 0xCA, 0x2D, 0x5D, 0x48, 0x8C, 0x79, 0x7B, 0xBB, 0x4F, 0x47, 0xDC, 0x07, 0x10, 0x50, 0x15, 0xED, 0x6A, 0x1F, 0x33, 0x09, 0xEF, 0xCE }, ++ { 0x15, 0x80, 0xAF, 0xEE, 0xBE, 0xBB, 0x34, 0x6F, 0x94, 0xD5, 0x9F, 0xE6, 0x2D, 0xA0, 0xB7, 0x92, 0x37, 0xEA, 0xD7, 0xB1, 0x49, 0x1F, 0x56, 0x67, 0xA9, 0x0E, 0x45, 0xED, 0xF6, 0xCA, 0x8B, 0x03 }, ++ { 0x20, 0xBE, 0x1A, 0x87, 0x5B, 0x38, 0xC5, 0x73, 0xDD, 0x7F, 0xAA, 0xA0, 0xDE, 0x48, 0x9D, 0x65, 0x5C, 0x11, 0xEF, 0xB6, 0xA5, 0x52, 0x69, 0x8E, 0x07, 0xA2, 0xD3, 0x31, 0xB5, 0xF6, 0x55, 0xC3 }, ++ { 0xBE, 0x1F, 0xE3, 0xC4, 0xC0, 0x40, 0x18, 0xC5, 0x4C, 0x4A, 0x0F, 0x6B, 0x9A, 0x2E, 0xD3, 0xC5, 0x3A, 0xBE, 0x3A, 0x9F, 0x76, 0xB4, 0xD2, 0x6D, 0xE5, 0x6F, 0xC9, 0xAE, 0x95, 0x05, 0x9A, 0x99 }, ++ { 0xE3, 0xE3, 0xAC, 0xE5, 0x37, 0xEB, 0x3E, 0xDD, 0x84, 0x63, 0xD9, 0xAD, 0x35, 0x82, 0xE1, 0x3C, 0xF8, 0x65, 0x33, 0xFF, 0xDE, 0x43, 0xD6, 0x68, 0xDD, 0x2E, 0x93, 0xBB, 0xDB, 0xD7, 0x19, 0x5A }, ++ { 0x11, 0x0C, 0x50, 0xC0, 0xBF, 0x2C, 0x6E, 0x7A, 0xEB, 0x7E, 0x43, 0x5D, 0x92, 0xD1, 0x32, 0xAB, 0x66, 0x55, 0x16, 0x8E, 0x78, 0xA2, 0xDE, 0xCD, 0xEC, 0x33, 0x30, 0x77, 0x76, 0x84, 0xD9, 0xC1 }, ++ { 0xE9, 0xBA, 0x8F, 0x50, 0x5C, 0x9C, 0x80, 0xC0, 0x86, 0x66, 0xA7, 0x01, 0xF3, 0x36, 0x7E, 0x6C, 0xC6, 0x65, 0xF3, 0x4B, 0x22, 0xE7, 0x3C, 0x3C, 0x04, 0x17, 0xEB, 0x1C, 0x22, 0x06, 0x08, 0x2F }, ++ { 0x26, 0xCD, 0x66, 0xFC, 0xA0, 0x23, 0x79, 0xC7, 0x6D, 0xF1, 0x23, 0x17, 0x05, 0x2B, 0xCA, 0xFD, 0x6C, 0xD8, 0xC3, 0xA7, 0xB8, 0x90, 0xD8, 0x05, 0xF3, 0x6C, 0x49, 0x98, 0x97, 0x82, 0x43, 0x3A }, ++ { 0x21, 0x3F, 0x35, 0x96, 0xD6, 0xE3, 0xA5, 0xD0, 0xE9, 0x93, 0x2C, 0xD2, 0x15, 0x91, 0x46, 0x01, 0x5E, 0x2A, 0xBC, 0x94, 0x9F, 0x47, 0x29, 0xEE, 0x26, 0x32, 0xFE, 0x1E, 0xDB, 0x78, 0xD3, 0x37 }, ++ { 0x10, 0x15, 0xD7, 0x01, 0x08, 0xE0, 0x3B, 0xE1, 0xC7, 0x02, 0xFE, 0x97, 0x25, 0x36, 0x07, 0xD1, 0x4A, 0xEE, 0x59, 0x1F, 0x24, 0x13, 0xEA, 0x67, 0x87, 0x42, 0x7B, 0x64, 0x59, 0xFF, 0x21, 0x9A }, ++ { 0x3C, 0xA9, 0x89, 0xDE, 0x10, 0xCF, 0xE6, 0x09, 0x90, 0x94, 0x72, 0xC8, 0xD3, 0x56, 0x10, 0x80, 0x5B, 0x2F, 0x97, 0x77, 0x34, 0xCF, 0x65, 0x2C, 0xC6, 0x4B, 0x3B, 0xFC, 0x88, 0x2D, 0x5D, 0x89 }, ++ { 0xB6, 0x15, 0x6F, 0x72, 0xD3, 0x80, 0xEE, 0x9E, 0xA6, 0xAC, 0xD1, 0x90, 0x46, 0x4F, 0x23, 0x07, 0xA5, 0xC1, 0x79, 0xEF, 0x01, 0xFD, 0x71, 0xF9, 0x9F, 0x2D, 0x0F, 0x7A, 0x57, 0x36, 0x0A, 0xEA }, ++ { 0xC0, 0x3B, 0xC6, 0x42, 0xB2, 0x09, 0x59, 0xCB, 0xE1, 0x33, 0xA0, 0x30, 0x3E, 0x0C, 0x1A, 0xBF, 0xF3, 0xE3, 0x1E, 0xC8, 0xE1, 0xA3, 0x28, 0xEC, 0x85, 0x65, 0xC3, 0x6D, 0xEC, 0xFF, 0x52, 0x65 }, ++ { 0x2C, 0x3E, 0x08, 0x17, 0x6F, 0x76, 0x0C, 0x62, 0x64, 0xC3, 0xA2, 0xCD, 0x66, 0xFE, 0xC6, 0xC3, 0xD7, 0x8D, 0xE4, 0x3F, 0xC1, 0x92, 0x45, 0x7B, 0x2A, 0x4A, 0x66, 0x0A, 0x1E, 0x0E, 0xB2, 0x2B }, ++ { 0xF7, 0x38, 0xC0, 0x2F, 0x3C, 0x1B, 0x19, 0x0C, 0x51, 0x2B, 0x1A, 0x32, 0xDE, 0xAB, 0xF3, 0x53, 0x72, 0x8E, 0x0E, 0x9A, 0xB0, 0x34, 0x49, 0x0E, 0x3C, 0x34, 0x09, 0x94, 0x6A, 0x97, 0xAE, 0xEC }, ++ { 0x8B, 0x18, 0x80, 0xDF, 0x30, 0x1C, 0xC9, 0x63, 0x41, 0x88, 0x11, 0x08, 0x89, 0x64, 0x83, 0x92, 0x87, 0xFF, 0x7F, 0xE3, 0x1C, 0x49, 0xEA, 0x6E, 0xBD, 0x9E, 0x48, 0xBD, 0xEE, 0xE4, 0x97, 0xC5 }, ++ { 0x1E, 0x75, 0xCB, 0x21, 0xC6, 0x09, 0x89, 0x02, 0x03, 0x75, 0xF1, 0xA7, 0xA2, 0x42, 0x83, 0x9F, 0x0B, 0x0B, 0x68, 0x97, 0x3A, 0x4C, 0x2A, 0x05, 0xCF, 0x75, 0x55, 0xED, 0x5A, 0xAE, 0xC4, 0xC1 }, ++ { 0x62, 0xBF, 0x8A, 0x9C, 0x32, 0xA5, 0xBC, 0xCF, 0x29, 0x0B, 0x6C, 0x47, 0x4D, 0x75, 0xB2, 0xA2, 0xA4, 0x09, 0x3F, 0x1A, 0x9E, 0x27, 0x13, 0x94, 0x33, 0xA8, 0xF2, 0xB3, 0xBC, 0xE7, 0xB8, 0xD7 }, ++ { 0x16, 0x6C, 0x83, 0x50, 0xD3, 0x17, 0x3B, 0x5E, 0x70, 0x2B, 0x78, 0x3D, 0xFD, 0x33, 0xC6, 0x6E, 0xE0, 0x43, 0x27, 0x42, 0xE9, 0xB9, 0x2B, 0x99, 0x7F, 0xD2, 0x3C, 0x60, 0xDC, 0x67, 0x56, 0xCA }, ++ { 0x04, 0x4A, 0x14, 0xD8, 0x22, 0xA9, 0x0C, 0xAC, 0xF2, 0xF5, 0xA1, 0x01, 0x42, 0x8A, 0xDC, 0x8F, 0x41, 0x09, 0x38, 0x6C, 0xCB, 0x15, 0x8B, 0xF9, 0x05, 0xC8, 0x61, 0x8B, 0x8E, 0xE2, 0x4E, 0xC3 }, ++ { 0x38, 0x7D, 0x39, 0x7E, 0xA4, 0x3A, 0x99, 0x4B, 0xE8, 0x4D, 0x2D, 0x54, 0x4A, 0xFB, 0xE4, 0x81, 0xA2, 0x00, 0x0F, 0x55, 0x25, 0x26, 0x96, 0xBB, 0xA2, 0xC5, 0x0C, 0x8E, 0xBD, 0x10, 0x13, 0x47 }, ++ { 0x56, 0xF8, 0xCC, 0xF1, 0xF8, 0x64, 0x09, 0xB4, 0x6C, 0xE3, 0x61, 0x66, 0xAE, 0x91, 0x65, 0x13, 0x84, 0x41, 0x57, 0x75, 0x89, 0xDB, 0x08, 0xCB, 0xC5, 0xF6, 0x6C, 0xA2, 0x97, 0x43, 0xB9, 0xFD }, ++ { 0x97, 0x06, 0xC0, 0x92, 0xB0, 0x4D, 0x91, 0xF5, 0x3D, 0xFF, 0x91, 0xFA, 0x37, 0xB7, 0x49, 0x3D, 0x28, 0xB5, 0x76, 0xB5, 0xD7, 0x10, 0x46, 0x9D, 0xF7, 0x94, 0x01, 0x66, 0x22, 0x36, 0xFC, 0x03 }, ++ { 0x87, 0x79, 0x68, 0x68, 0x6C, 0x06, 0x8C, 0xE2, 0xF7, 0xE2, 0xAD, 0xCF, 0xF6, 0x8B, 0xF8, 0x74, 0x8E, 0xDF, 0x3C, 0xF8, 0x62, 0xCF, 0xB4, 0xD3, 0x94, 0x7A, 0x31, 0x06, 0x95, 0x80, 0x54, 0xE3 }, ++ { 0x88, 0x17, 0xE5, 0x71, 0x98, 0x79, 0xAC, 0xF7, 0x02, 0x47, 0x87, 0xEC, 0xCD, 0xB2, 0x71, 0x03, 0x55, 0x66, 0xCF, 0xA3, 0x33, 0xE0, 0x49, 0x40, 0x7C, 0x01, 0x78, 0xCC, 0xC5, 0x7A, 0x5B, 0x9F }, ++ { 0x89, 0x38, 0x24, 0x9E, 0x4B, 0x50, 0xCA, 0xDA, 0xCC, 0xDF, 0x5B, 0x18, 0x62, 0x13, 0x26, 0xCB, 0xB1, 0x52, 0x53, 0xE3, 0x3A, 0x20, 0xF5, 0x63, 0x6E, 0x99, 0x5D, 0x72, 0x47, 0x8D, 0xE4, 0x72 }, ++ { 0xF1, 0x64, 0xAB, 0xBA, 0x49, 0x63, 0xA4, 0x4D, 0x10, 0x72, 0x57, 0xE3, 0x23, 0x2D, 0x90, 0xAC, 0xA5, 0xE6, 0x6A, 0x14, 0x08, 0x24, 0x8C, 0x51, 0x74, 0x1E, 0x99, 0x1D, 0xB5, 0x22, 0x77, 0x56 }, ++ { 0xD0, 0x55, 0x63, 0xE2, 0xB1, 0xCB, 0xA0, 0xC4, 0xA2, 0xA1, 0xE8, 0xBD, 0xE3, 0xA1, 0xA0, 0xD9, 0xF5, 0xB4, 0x0C, 0x85, 0xA0, 0x70, 0xD6, 0xF5, 0xFB, 0x21, 0x06, 0x6E, 0xAD, 0x5D, 0x06, 0x01 }, ++ { 0x03, 0xFB, 0xB1, 0x63, 0x84, 0xF0, 0xA3, 0x86, 0x6F, 0x4C, 0x31, 0x17, 0x87, 0x76, 0x66, 0xEF, 0xBF, 0x12, 0x45, 0x97, 0x56, 0x4B, 0x29, 0x3D, 0x4A, 0xAB, 0x0D, 0x26, 0x9F, 0xAB, 0xDD, 0xFA }, ++ { 0x5F, 0xA8, 0x48, 0x6A, 0xC0, 0xE5, 0x29, 0x64, 0xD1, 0x88, 0x1B, 0xBE, 0x33, 0x8E, 0xB5, 0x4B, 0xE2, 0xF7, 0x19, 0x54, 0x92, 0x24, 0x89, 0x20, 0x57, 0xB4, 0xDA, 0x04, 0xBA, 0x8B, 0x34, 0x75 }, ++ { 0xCD, 0xFA, 0xBC, 0xEE, 0x46, 0x91, 0x11, 0x11, 0x23, 0x6A, 0x31, 0x70, 0x8B, 0x25, 0x39, 0xD7, 0x1F, 0xC2, 0x11, 0xD9, 0xB0, 0x9C, 0x0D, 0x85, 0x30, 0xA1, 0x1E, 0x1D, 0xBF, 0x6E, 0xED, 0x01 }, ++ { 0x4F, 0x82, 0xDE, 0x03, 0xB9, 0x50, 0x47, 0x93, 0xB8, 0x2A, 0x07, 0xA0, 0xBD, 0xCD, 0xFF, 0x31, 0x4D, 0x75, 0x9E, 0x7B, 0x62, 0xD2, 0x6B, 0x78, 0x49, 0x46, 0xB0, 0xD3, 0x6F, 0x91, 0x6F, 0x52 }, ++ { 0x25, 0x9E, 0xC7, 0xF1, 0x73, 0xBC, 0xC7, 0x6A, 0x09, 0x94, 0xC9, 0x67, 0xB4, 0xF5, 0xF0, 0x24, 0xC5, 0x60, 0x57, 0xFB, 0x79, 0xC9, 0x65, 0xC4, 0xFA, 0xE4, 0x18, 0x75, 0xF0, 0x6A, 0x0E, 0x4C }, ++ { 0x19, 0x3C, 0xC8, 0xE7, 0xC3, 0xE0, 0x8B, 0xB3, 0x0F, 0x54, 0x37, 0xAA, 0x27, 0xAD, 0xE1, 0xF1, 0x42, 0x36, 0x9B, 0x24, 0x6A, 0x67, 0x5B, 0x23, 0x83, 0xE6, 0xDA, 0x9B, 0x49, 0xA9, 0x80, 0x9E }, ++ { 0x5C, 0x10, 0x89, 0x6F, 0x0E, 0x28, 0x56, 0xB2, 0xA2, 0xEE, 0xE0, 0xFE, 0x4A, 0x2C, 0x16, 0x33, 0x56, 0x5D, 0x18, 0xF0, 0xE9, 0x3E, 0x1F, 0xAB, 0x26, 0xC3, 0x73, 0xE8, 0xF8, 0x29, 0x65, 0x4D }, ++ { 0xF1, 0x60, 0x12, 0xD9, 0x3F, 0x28, 0x85, 0x1A, 0x1E, 0xB9, 0x89, 0xF5, 0xD0, 0xB4, 0x3F, 0x3F, 0x39, 0xCA, 0x73, 0xC9, 0xA6, 0x2D, 0x51, 0x81, 0xBF, 0xF2, 0x37, 0x53, 0x6B, 0xD3, 0x48, 0xC3 }, ++ { 0x29, 0x66, 0xB3, 0xCF, 0xAE, 0x1E, 0x44, 0xEA, 0x99, 0x6D, 0xC5, 0xD6, 0x86, 0xCF, 0x25, 0xFA, 0x05, 0x3F, 0xB6, 0xF6, 0x72, 0x01, 0xB9, 0xE4, 0x6E, 0xAD, 0xE8, 0x5D, 0x0A, 0xD6, 0xB8, 0x06 }, ++ { 0xDD, 0xB8, 0x78, 0x24, 0x85, 0xE9, 0x00, 0xBC, 0x60, 0xBC, 0xF4, 0xC3, 0x3A, 0x6F, 0xD5, 0x85, 0x68, 0x0C, 0xC6, 0x83, 0xD5, 0x16, 0xEF, 0xA0, 0x3E, 0xB9, 0x98, 0x5F, 0xAD, 0x87, 0x15, 0xFB }, ++ { 0x4C, 0x4D, 0x6E, 0x71, 0xAE, 0xA0, 0x57, 0x86, 0x41, 0x31, 0x48, 0xFC, 0x7A, 0x78, 0x6B, 0x0E, 0xCA, 0xF5, 0x82, 0xCF, 0xF1, 0x20, 0x9F, 0x5A, 0x80, 0x9F, 0xBA, 0x85, 0x04, 0xCE, 0x66, 0x2C }, ++ { 0xFB, 0x4C, 0x5E, 0x86, 0xD7, 0xB2, 0x22, 0x9B, 0x99, 0xB8, 0xBA, 0x6D, 0x94, 0xC2, 0x47, 0xEF, 0x96, 0x4A, 0xA3, 0xA2, 0xBA, 0xE8, 0xED, 0xC7, 0x75, 0x69, 0xF2, 0x8D, 0xBB, 0xFF, 0x2D, 0x4E }, ++ { 0xE9, 0x4F, 0x52, 0x6D, 0xE9, 0x01, 0x96, 0x33, 0xEC, 0xD5, 0x4A, 0xC6, 0x12, 0x0F, 0x23, 0x95, 0x8D, 0x77, 0x18, 0xF1, 0xE7, 0x71, 0x7B, 0xF3, 0x29, 0x21, 0x1A, 0x4F, 0xAE, 0xED, 0x4E, 0x6D }, ++ { 0xCB, 0xD6, 0x66, 0x0A, 0x10, 0xDB, 0x3F, 0x23, 0xF7, 0xA0, 0x3D, 0x4B, 0x9D, 0x40, 0x44, 0xC7, 0x93, 0x2B, 0x28, 0x01, 0xAC, 0x89, 0xD6, 0x0B, 0xC9, 0xEB, 0x92, 0xD6, 0x5A, 0x46, 0xC2, 0xA0 }, ++ { 0x88, 0x18, 0xBB, 0xD3, 0xDB, 0x4D, 0xC1, 0x23, 0xB2, 0x5C, 0xBB, 0xA5, 0xF5, 0x4C, 0x2B, 0xC4, 0xB3, 0xFC, 0xF9, 0xBF, 0x7D, 0x7A, 0x77, 0x09, 0xF4, 0xAE, 0x58, 0x8B, 0x26, 0x7C, 0x4E, 0xCE }, ++ { 0xC6, 0x53, 0x82, 0x51, 0x3F, 0x07, 0x46, 0x0D, 0xA3, 0x98, 0x33, 0xCB, 0x66, 0x6C, 0x5E, 0xD8, 0x2E, 0x61, 0xB9, 0xE9, 0x98, 0xF4, 0xB0, 0xC4, 0x28, 0x7C, 0xEE, 0x56, 0xC3, 0xCC, 0x9B, 0xCD }, ++ { 0x89, 0x75, 0xB0, 0x57, 0x7F, 0xD3, 0x55, 0x66, 0xD7, 0x50, 0xB3, 0x62, 0xB0, 0x89, 0x7A, 0x26, 0xC3, 0x99, 0x13, 0x6D, 0xF0, 0x7B, 0xAB, 0xAB, 0xBD, 0xE6, 0x20, 0x3F, 0xF2, 0x95, 0x4E, 0xD4 }, ++ { 0x21, 0xFE, 0x0C, 0xEB, 0x00, 0x52, 0xBE, 0x7F, 0xB0, 0xF0, 0x04, 0x18, 0x7C, 0xAC, 0xD7, 0xDE, 0x67, 0xFA, 0x6E, 0xB0, 0x93, 0x8D, 0x92, 0x76, 0x77, 0xF2, 0x39, 0x8C, 0x13, 0x23, 0x17, 0xA8 }, ++ { 0x2E, 0xF7, 0x3F, 0x3C, 0x26, 0xF1, 0x2D, 0x93, 0x88, 0x9F, 0x3C, 0x78, 0xB6, 0xA6, 0x6C, 0x1D, 0x52, 0xB6, 0x49, 0xDC, 0x9E, 0x85, 0x6E, 0x2C, 0x17, 0x2E, 0xA7, 0xC5, 0x8A, 0xC2, 0xB5, 0xE3 }, ++ { 0x38, 0x8A, 0x3C, 0xD5, 0x6D, 0x73, 0x86, 0x7A, 0xBB, 0x5F, 0x84, 0x01, 0x49, 0x2B, 0x6E, 0x26, 0x81, 0xEB, 0x69, 0x85, 0x1E, 0x76, 0x7F, 0xD8, 0x42, 0x10, 0xA5, 0x60, 0x76, 0xFB, 0x3D, 0xD3 }, ++ { 0xAF, 0x53, 0x3E, 0x02, 0x2F, 0xC9, 0x43, 0x9E, 0x4E, 0x3C, 0xB8, 0x38, 0xEC, 0xD1, 0x86, 0x92, 0x23, 0x2A, 0xDF, 0x6F, 0xE9, 0x83, 0x95, 0x26, 0xD3, 0xC3, 0xDD, 0x1B, 0x71, 0x91, 0x0B, 0x1A }, ++ { 0x75, 0x1C, 0x09, 0xD4, 0x1A, 0x93, 0x43, 0x88, 0x2A, 0x81, 0xCD, 0x13, 0xEE, 0x40, 0x81, 0x8D, 0x12, 0xEB, 0x44, 0xC6, 0xC7, 0xF4, 0x0D, 0xF1, 0x6E, 0x4A, 0xEA, 0x8F, 0xAB, 0x91, 0x97, 0x2A }, ++ { 0x5B, 0x73, 0xDD, 0xB6, 0x8D, 0x9D, 0x2B, 0x0A, 0xA2, 0x65, 0xA0, 0x79, 0x88, 0xD6, 0xB8, 0x8A, 0xE9, 0xAA, 0xC5, 0x82, 0xAF, 0x83, 0x03, 0x2F, 0x8A, 0x9B, 0x21, 0xA2, 0xE1, 0xB7, 0xBF, 0x18 }, ++ { 0x3D, 0xA2, 0x91, 0x26, 0xC7, 0xC5, 0xD7, 0xF4, 0x3E, 0x64, 0x24, 0x2A, 0x79, 0xFE, 0xAA, 0x4E, 0xF3, 0x45, 0x9C, 0xDE, 0xCC, 0xC8, 0x98, 0xED, 0x59, 0xA9, 0x7F, 0x6E, 0xC9, 0x3B, 0x9D, 0xAB }, ++ { 0x56, 0x6D, 0xC9, 0x20, 0x29, 0x3D, 0xA5, 0xCB, 0x4F, 0xE0, 0xAA, 0x8A, 0xBD, 0xA8, 0xBB, 0xF5, 0x6F, 0x55, 0x23, 0x13, 0xBF, 0xF1, 0x90, 0x46, 0x64, 0x1E, 0x36, 0x15, 0xC1, 0xE3, 0xED, 0x3F }, ++ { 0x41, 0x15, 0xBE, 0xA0, 0x2F, 0x73, 0xF9, 0x7F, 0x62, 0x9E, 0x5C, 0x55, 0x90, 0x72, 0x0C, 0x01, 0xE7, 0xE4, 0x49, 0xAE, 0x2A, 0x66, 0x97, 0xD4, 0xD2, 0x78, 0x33, 0x21, 0x30, 0x36, 0x92, 0xF9 }, ++ { 0x4C, 0xE0, 0x8F, 0x47, 0x62, 0x46, 0x8A, 0x76, 0x70, 0x01, 0x21, 0x64, 0x87, 0x8D, 0x68, 0x34, 0x0C, 0x52, 0xA3, 0x5E, 0x66, 0xC1, 0x88, 0x4D, 0x5C, 0x86, 0x48, 0x89, 0xAB, 0xC9, 0x66, 0x77 }, ++ { 0x81, 0xEA, 0x0B, 0x78, 0x04, 0x12, 0x4E, 0x0C, 0x22, 0xEA, 0x5F, 0xC7, 0x11, 0x04, 0xA2, 0xAF, 0xCB, 0x52, 0xA1, 0xFA, 0x81, 0x6F, 0x3E, 0xCB, 0x7D, 0xCB, 0x5D, 0x9D, 0xEA, 0x17, 0x86, 0xD0 }, ++ { 0xFE, 0x36, 0x27, 0x33, 0xB0, 0x5F, 0x6B, 0xED, 0xAF, 0x93, 0x79, 0xD7, 0xF7, 0x93, 0x6E, 0xDE, 0x20, 0x9B, 0x1F, 0x83, 0x23, 0xC3, 0x92, 0x25, 0x49, 0xD9, 0xE7, 0x36, 0x81, 0xB5, 0xDB, 0x7B }, ++ { 0xEF, 0xF3, 0x7D, 0x30, 0xDF, 0xD2, 0x03, 0x59, 0xBE, 0x4E, 0x73, 0xFD, 0xF4, 0x0D, 0x27, 0x73, 0x4B, 0x3D, 0xF9, 0x0A, 0x97, 0xA5, 0x5E, 0xD7, 0x45, 0x29, 0x72, 0x94, 0xCA, 0x85, 0xD0, 0x9F }, ++ { 0x17, 0x2F, 0xFC, 0x67, 0x15, 0x3D, 0x12, 0xE0, 0xCA, 0x76, 0xA8, 0xB6, 0xCD, 0x5D, 0x47, 0x31, 0x88, 0x5B, 0x39, 0xCE, 0x0C, 0xAC, 0x93, 0xA8, 0x97, 0x2A, 0x18, 0x00, 0x6C, 0x8B, 0x8B, 0xAF }, ++ { 0xC4, 0x79, 0x57, 0xF1, 0xCC, 0x88, 0xE8, 0x3E, 0xF9, 0x44, 0x58, 0x39, 0x70, 0x9A, 0x48, 0x0A, 0x03, 0x6B, 0xED, 0x5F, 0x88, 0xAC, 0x0F, 0xCC, 0x8E, 0x1E, 0x70, 0x3F, 0xFA, 0xAC, 0x13, 0x2C }, ++ { 0x30, 0xF3, 0x54, 0x83, 0x70, 0xCF, 0xDC, 0xED, 0xA5, 0xC3, 0x7B, 0x56, 0x9B, 0x61, 0x75, 0xE7, 0x99, 0xEE, 0xF1, 0xA6, 0x2A, 0xAA, 0x94, 0x32, 0x45, 0xAE, 0x76, 0x69, 0xC2, 0x27, 0xA7, 0xB5 }, ++ { 0xC9, 0x5D, 0xCB, 0x3C, 0xF1, 0xF2, 0x7D, 0x0E, 0xEF, 0x2F, 0x25, 0xD2, 0x41, 0x38, 0x70, 0x90, 0x4A, 0x87, 0x7C, 0x4A, 0x56, 0xC2, 0xDE, 0x1E, 0x83, 0xE2, 0xBC, 0x2A, 0xE2, 0xE4, 0x68, 0x21 }, ++ { 0xD5, 0xD0, 0xB5, 0xD7, 0x05, 0x43, 0x4C, 0xD4, 0x6B, 0x18, 0x57, 0x49, 0xF6, 0x6B, 0xFB, 0x58, 0x36, 0xDC, 0xDF, 0x6E, 0xE5, 0x49, 0xA2, 0xB7, 0xA4, 0xAE, 0xE7, 0xF5, 0x80, 0x07, 0xCA, 0xAF }, ++ { 0xBB, 0xC1, 0x24, 0xA7, 0x12, 0xF1, 0x5D, 0x07, 0xC3, 0x00, 0xE0, 0x5B, 0x66, 0x83, 0x89, 0xA4, 0x39, 0xC9, 0x17, 0x77, 0xF7, 0x21, 0xF8, 0x32, 0x0C, 0x1C, 0x90, 0x78, 0x06, 0x6D, 0x2C, 0x7E }, ++ { 0xA4, 0x51, 0xB4, 0x8C, 0x35, 0xA6, 0xC7, 0x85, 0x4C, 0xFA, 0xAE, 0x60, 0x26, 0x2E, 0x76, 0x99, 0x08, 0x16, 0x38, 0x2A, 0xC0, 0x66, 0x7E, 0x5A, 0x5C, 0x9E, 0x1B, 0x46, 0xC4, 0x34, 0x2D, 0xDF }, ++ { 0xB0, 0xD1, 0x50, 0xFB, 0x55, 0xE7, 0x78, 0xD0, 0x11, 0x47, 0xF0, 0xB5, 0xD8, 0x9D, 0x99, 0xEC, 0xB2, 0x0F, 0xF0, 0x7E, 0x5E, 0x67, 0x60, 0xD6, 0xB6, 0x45, 0xEB, 0x5B, 0x65, 0x4C, 0x62, 0x2B }, ++ { 0x34, 0xF7, 0x37, 0xC0, 0xAB, 0x21, 0x99, 0x51, 0xEE, 0xE8, 0x9A, 0x9F, 0x8D, 0xAC, 0x29, 0x9C, 0x9D, 0x4C, 0x38, 0xF3, 0x3F, 0xA4, 0x94, 0xC5, 0xC6, 0xEE, 0xFC, 0x92, 0xB6, 0xDB, 0x08, 0xBC }, ++ { 0x1A, 0x62, 0xCC, 0x3A, 0x00, 0x80, 0x0D, 0xCB, 0xD9, 0x98, 0x91, 0x08, 0x0C, 0x1E, 0x09, 0x84, 0x58, 0x19, 0x3A, 0x8C, 0xC9, 0xF9, 0x70, 0xEA, 0x99, 0xFB, 0xEF, 0xF0, 0x03, 0x18, 0xC2, 0x89 }, ++ { 0xCF, 0xCE, 0x55, 0xEB, 0xAF, 0xC8, 0x40, 0xD7, 0xAE, 0x48, 0x28, 0x1C, 0x7F, 0xD5, 0x7E, 0xC8, 0xB4, 0x82, 0xD4, 0xB7, 0x04, 0x43, 0x74, 0x95, 0x49, 0x5A, 0xC4, 0x14, 0xCF, 0x4A, 0x37, 0x4B }, ++ { 0x67, 0x46, 0xFA, 0xCF, 0x71, 0x14, 0x6D, 0x99, 0x9D, 0xAB, 0xD0, 0x5D, 0x09, 0x3A, 0xE5, 0x86, 0x64, 0x8D, 0x1E, 0xE2, 0x8E, 0x72, 0x61, 0x7B, 0x99, 0xD0, 0xF0, 0x08, 0x6E, 0x1E, 0x45, 0xBF }, ++ { 0x57, 0x1C, 0xED, 0x28, 0x3B, 0x3F, 0x23, 0xB4, 0xE7, 0x50, 0xBF, 0x12, 0xA2, 0xCA, 0xF1, 0x78, 0x18, 0x47, 0xBD, 0x89, 0x0E, 0x43, 0x60, 0x3C, 0xDC, 0x59, 0x76, 0x10, 0x2B, 0x7B, 0xB1, 0x1B }, ++ { 0xCF, 0xCB, 0x76, 0x5B, 0x04, 0x8E, 0x35, 0x02, 0x2C, 0x5D, 0x08, 0x9D, 0x26, 0xE8, 0x5A, 0x36, 0xB0, 0x05, 0xA2, 0xB8, 0x04, 0x93, 0xD0, 0x3A, 0x14, 0x4E, 0x09, 0xF4, 0x09, 0xB6, 0xAF, 0xD1 }, ++ { 0x40, 0x50, 0xC7, 0xA2, 0x77, 0x05, 0xBB, 0x27, 0xF4, 0x20, 0x89, 0xB2, 0x99, 0xF3, 0xCB, 0xE5, 0x05, 0x4E, 0xAD, 0x68, 0x72, 0x7E, 0x8E, 0xF9, 0x31, 0x8C, 0xE6, 0xF2, 0x5C, 0xD6, 0xF3, 0x1D }, ++ { 0x18, 0x40, 0x70, 0xBD, 0x5D, 0x26, 0x5F, 0xBD, 0xC1, 0x42, 0xCD, 0x1C, 0x5C, 0xD0, 0xD7, 0xE4, 0x14, 0xE7, 0x03, 0x69, 0xA2, 0x66, 0xD6, 0x27, 0xC8, 0xFB, 0xA8, 0x4F, 0xA5, 0xE8, 0x4C, 0x34 }, ++ { 0x9E, 0xDD, 0xA9, 0xA4, 0x44, 0x39, 0x02, 0xA9, 0x58, 0x8C, 0x0D, 0x0C, 0xCC, 0x62, 0xB9, 0x30, 0x21, 0x84, 0x79, 0xA6, 0x84, 0x1E, 0x6F, 0xE7, 0xD4, 0x30, 0x03, 0xF0, 0x4B, 0x1F, 0xD6, 0x43 }, ++ { 0xE4, 0x12, 0xFE, 0xEF, 0x79, 0x08, 0x32, 0x4A, 0x6D, 0xA1, 0x84, 0x16, 0x29, 0xF3, 0x5D, 0x3D, 0x35, 0x86, 0x42, 0x01, 0x93, 0x10, 0xEC, 0x57, 0xC6, 0x14, 0x83, 0x6B, 0x63, 0xD3, 0x07, 0x63 }, ++ { 0x1A, 0x2B, 0x8E, 0xDF, 0xF3, 0xF9, 0xAC, 0xC1, 0x55, 0x4F, 0xCB, 0xAE, 0x3C, 0xF1, 0xD6, 0x29, 0x8C, 0x64, 0x62, 0xE2, 0x2E, 0x5E, 0xB0, 0x25, 0x96, 0x84, 0xF8, 0x35, 0x01, 0x2B, 0xD1, 0x3F }, ++ { 0x28, 0x8C, 0x4A, 0xD9, 0xB9, 0x40, 0x97, 0x62, 0xEA, 0x07, 0xC2, 0x4A, 0x41, 0xF0, 0x4F, 0x69, 0xA7, 0xD7, 0x4B, 0xEE, 0x2D, 0x95, 0x43, 0x53, 0x74, 0xBD, 0xE9, 0x46, 0xD7, 0x24, 0x1C, 0x7B }, ++ { 0x80, 0x56, 0x91, 0xBB, 0x28, 0x67, 0x48, 0xCF, 0xB5, 0x91, 0xD3, 0xAE, 0xBE, 0x7E, 0x6F, 0x4E, 0x4D, 0xC6, 0xE2, 0x80, 0x8C, 0x65, 0x14, 0x3C, 0xC0, 0x04, 0xE4, 0xEB, 0x6F, 0xD0, 0x9D, 0x43 }, ++ { 0xD4, 0xAC, 0x8D, 0x3A, 0x0A, 0xFC, 0x6C, 0xFA, 0x7B, 0x46, 0x0A, 0xE3, 0x00, 0x1B, 0xAE, 0xB3, 0x6D, 0xAD, 0xB3, 0x7D, 0xA0, 0x7D, 0x2E, 0x8A, 0xC9, 0x18, 0x22, 0xDF, 0x34, 0x8A, 0xED, 0x3D }, ++ { 0xC3, 0x76, 0x61, 0x70, 0x14, 0xD2, 0x01, 0x58, 0xBC, 0xED, 0x3D, 0x3B, 0xA5, 0x52, 0xB6, 0xEC, 0xCF, 0x84, 0xE6, 0x2A, 0xA3, 0xEB, 0x65, 0x0E, 0x90, 0x02, 0x9C, 0x84, 0xD1, 0x3E, 0xEA, 0x69 }, ++ { 0xC4, 0x1F, 0x09, 0xF4, 0x3C, 0xEC, 0xAE, 0x72, 0x93, 0xD6, 0x00, 0x7C, 0xA0, 0xA3, 0x57, 0x08, 0x7D, 0x5A, 0xE5, 0x9B, 0xE5, 0x00, 0xC1, 0xCD, 0x5B, 0x28, 0x9E, 0xE8, 0x10, 0xC7, 0xB0, 0x82 }, ++ { 0x03, 0xD1, 0xCE, 0xD1, 0xFB, 0xA5, 0xC3, 0x91, 0x55, 0xC4, 0x4B, 0x77, 0x65, 0xCB, 0x76, 0x0C, 0x78, 0x70, 0x8D, 0xCF, 0xC8, 0x0B, 0x0B, 0xD8, 0xAD, 0xE3, 0xA5, 0x6D, 0xA8, 0x83, 0x0B, 0x29 }, ++ { 0x09, 0xBD, 0xE6, 0xF1, 0x52, 0x21, 0x8D, 0xC9, 0x2C, 0x41, 0xD7, 0xF4, 0x53, 0x87, 0xE6, 0x3E, 0x58, 0x69, 0xD8, 0x07, 0xEC, 0x70, 0xB8, 0x21, 0x40, 0x5D, 0xBD, 0x88, 0x4B, 0x7F, 0xCF, 0x4B }, ++ { 0x71, 0xC9, 0x03, 0x6E, 0x18, 0x17, 0x9B, 0x90, 0xB3, 0x7D, 0x39, 0xE9, 0xF0, 0x5E, 0xB8, 0x9C, 0xC5, 0xFC, 0x34, 0x1F, 0xD7, 0xC4, 0x77, 0xD0, 0xD7, 0x49, 0x32, 0x85, 0xFA, 0xCA, 0x08, 0xA4 }, ++ { 0x59, 0x16, 0x83, 0x3E, 0xBB, 0x05, 0xCD, 0x91, 0x9C, 0xA7, 0xFE, 0x83, 0xB6, 0x92, 0xD3, 0x20, 0x5B, 0xEF, 0x72, 0x39, 0x2B, 0x2C, 0xF6, 0xBB, 0x0A, 0x6D, 0x43, 0xF9, 0x94, 0xF9, 0x5F, 0x11 }, ++ { 0xF6, 0x3A, 0xAB, 0x3E, 0xC6, 0x41, 0xB3, 0xB0, 0x24, 0x96, 0x4C, 0x2B, 0x43, 0x7C, 0x04, 0xF6, 0x04, 0x3C, 0x4C, 0x7E, 0x02, 0x79, 0x23, 0x99, 0x95, 0x40, 0x19, 0x58, 0xF8, 0x6B, 0xBE, 0x54 }, ++ { 0xF1, 0x72, 0xB1, 0x80, 0xBF, 0xB0, 0x97, 0x40, 0x49, 0x31, 0x20, 0xB6, 0x32, 0x6C, 0xBD, 0xC5, 0x61, 0xE4, 0x77, 0xDE, 0xF9, 0xBB, 0xCF, 0xD2, 0x8C, 0xC8, 0xC1, 0xC5, 0xE3, 0x37, 0x9A, 0x31 }, ++ { 0xCB, 0x9B, 0x89, 0xCC, 0x18, 0x38, 0x1D, 0xD9, 0x14, 0x1A, 0xDE, 0x58, 0x86, 0x54, 0xD4, 0xE6, 0xA2, 0x31, 0xD5, 0xBF, 0x49, 0xD4, 0xD5, 0x9A, 0xC2, 0x7D, 0x86, 0x9C, 0xBE, 0x10, 0x0C, 0xF3 }, ++ { 0x7B, 0xD8, 0x81, 0x50, 0x46, 0xFD, 0xD8, 0x10, 0xA9, 0x23, 0xE1, 0x98, 0x4A, 0xAE, 0xBD, 0xCD, 0xF8, 0x4D, 0x87, 0xC8, 0x99, 0x2D, 0x68, 0xB5, 0xEE, 0xB4, 0x60, 0xF9, 0x3E, 0xB3, 0xC8, 0xD7 }, ++ { 0x60, 0x7B, 0xE6, 0x68, 0x62, 0xFD, 0x08, 0xEE, 0x5B, 0x19, 0xFA, 0xCA, 0xC0, 0x9D, 0xFD, 0xBC, 0xD4, 0x0C, 0x31, 0x21, 0x01, 0xD6, 0x6E, 0x6E, 0xBD, 0x2B, 0x84, 0x1F, 0x1B, 0x9A, 0x93, 0x25 }, ++ { 0x9F, 0xE0, 0x3B, 0xBE, 0x69, 0xAB, 0x18, 0x34, 0xF5, 0x21, 0x9B, 0x0D, 0xA8, 0x8A, 0x08, 0xB3, 0x0A, 0x66, 0xC5, 0x91, 0x3F, 0x01, 0x51, 0x96, 0x3C, 0x36, 0x05, 0x60, 0xDB, 0x03, 0x87, 0xB3 }, ++ { 0x90, 0xA8, 0x35, 0x85, 0x71, 0x7B, 0x75, 0xF0, 0xE9, 0xB7, 0x25, 0xE0, 0x55, 0xEE, 0xEE, 0xB9, 0xE7, 0xA0, 0x28, 0xEA, 0x7E, 0x6C, 0xBC, 0x07, 0xB2, 0x09, 0x17, 0xEC, 0x03, 0x63, 0xE3, 0x8C }, ++ { 0x33, 0x6E, 0xA0, 0x53, 0x0F, 0x4A, 0x74, 0x69, 0x12, 0x6E, 0x02, 0x18, 0x58, 0x7E, 0xBB, 0xDE, 0x33, 0x58, 0xA0, 0xB3, 0x1C, 0x29, 0xD2, 0x00, 0xF7, 0xDC, 0x7E, 0xB1, 0x5C, 0x6A, 0xAD, 0xD8 }, ++ { 0xA7, 0x9E, 0x76, 0xDC, 0x0A, 0xBC, 0xA4, 0x39, 0x6F, 0x07, 0x47, 0xCD, 0x7B, 0x74, 0x8D, 0xF9, 0x13, 0x00, 0x76, 0x26, 0xB1, 0xD6, 0x59, 0xDA, 0x0C, 0x1F, 0x78, 0xB9, 0x30, 0x3D, 0x01, 0xA3 }, ++ { 0x44, 0xE7, 0x8A, 0x77, 0x37, 0x56, 0xE0, 0x95, 0x15, 0x19, 0x50, 0x4D, 0x70, 0x38, 0xD2, 0x8D, 0x02, 0x13, 0xA3, 0x7E, 0x0C, 0xE3, 0x75, 0x37, 0x17, 0x57, 0xBC, 0x99, 0x63, 0x11, 0xE3, 0xB8 }, ++ { 0x77, 0xAC, 0x01, 0x2A, 0x3F, 0x75, 0x4D, 0xCF, 0xEA, 0xB5, 0xEB, 0x99, 0x6B, 0xE9, 0xCD, 0x2D, 0x1F, 0x96, 0x11, 0x1B, 0x6E, 0x49, 0xF3, 0x99, 0x4D, 0xF1, 0x81, 0xF2, 0x85, 0x69, 0xD8, 0x25 }, ++ { 0xCE, 0x5A, 0x10, 0xDB, 0x6F, 0xCC, 0xDA, 0xF1, 0x40, 0xAA, 0xA4, 0xDE, 0xD6, 0x25, 0x0A, 0x9C, 0x06, 0xE9, 0x22, 0x2B, 0xC9, 0xF9, 0xF3, 0x65, 0x8A, 0x4A, 0xFF, 0x93, 0x5F, 0x2B, 0x9F, 0x3A }, ++ { 0xEC, 0xC2, 0x03, 0xA7, 0xFE, 0x2B, 0xE4, 0xAB, 0xD5, 0x5B, 0xB5, 0x3E, 0x6E, 0x67, 0x35, 0x72, 0xE0, 0x07, 0x8D, 0xA8, 0xCD, 0x37, 0x5E, 0xF4, 0x30, 0xCC, 0x97, 0xF9, 0xF8, 0x00, 0x83, 0xAF }, ++ { 0x14, 0xA5, 0x18, 0x6D, 0xE9, 0xD7, 0xA1, 0x8B, 0x04, 0x12, 0xB8, 0x56, 0x3E, 0x51, 0xCC, 0x54, 0x33, 0x84, 0x0B, 0x4A, 0x12, 0x9A, 0x8F, 0xF9, 0x63, 0xB3, 0x3A, 0x3C, 0x4A, 0xFE, 0x8E, 0xBB }, ++ { 0x13, 0xF8, 0xEF, 0x95, 0xCB, 0x86, 0xE6, 0xA6, 0x38, 0x93, 0x1C, 0x8E, 0x10, 0x76, 0x73, 0xEB, 0x76, 0xBA, 0x10, 0xD7, 0xC2, 0xCD, 0x70, 0xB9, 0xD9, 0x92, 0x0B, 0xBE, 0xED, 0x92, 0x94, 0x09 }, ++ { 0x0B, 0x33, 0x8F, 0x4E, 0xE1, 0x2F, 0x2D, 0xFC, 0xB7, 0x87, 0x13, 0x37, 0x79, 0x41, 0xE0, 0xB0, 0x63, 0x21, 0x52, 0x58, 0x1D, 0x13, 0x32, 0x51, 0x6E, 0x4A, 0x2C, 0xAB, 0x19, 0x42, 0xCC, 0xA4 }, ++ { 0xEA, 0xAB, 0x0E, 0xC3, 0x7B, 0x3B, 0x8A, 0xB7, 0x96, 0xE9, 0xF5, 0x72, 0x38, 0xDE, 0x14, 0xA2, 0x64, 0xA0, 0x76, 0xF3, 0x88, 0x7D, 0x86, 0xE2, 0x9B, 0xB5, 0x90, 0x6D, 0xB5, 0xA0, 0x0E, 0x02 }, ++ { 0x23, 0xCB, 0x68, 0xB8, 0xC0, 0xE6, 0xDC, 0x26, 0xDC, 0x27, 0x76, 0x6D, 0xDC, 0x0A, 0x13, 0xA9, 0x94, 0x38, 0xFD, 0x55, 0x61, 0x7A, 0xA4, 0x09, 0x5D, 0x8F, 0x96, 0x97, 0x20, 0xC8, 0x72, 0xDF }, ++ { 0x09, 0x1D, 0x8E, 0xE3, 0x0D, 0x6F, 0x29, 0x68, 0xD4, 0x6B, 0x68, 0x7D, 0xD6, 0x52, 0x92, 0x66, 0x57, 0x42, 0xDE, 0x0B, 0xB8, 0x3D, 0xCC, 0x00, 0x04, 0xC7, 0x2C, 0xE1, 0x00, 0x07, 0xA5, 0x49 }, ++ { 0x7F, 0x50, 0x7A, 0xBC, 0x6D, 0x19, 0xBA, 0x00, 0xC0, 0x65, 0xA8, 0x76, 0xEC, 0x56, 0x57, 0x86, 0x88, 0x82, 0xD1, 0x8A, 0x22, 0x1B, 0xC4, 0x6C, 0x7A, 0x69, 0x12, 0x54, 0x1F, 0x5B, 0xC7, 0xBA }, ++ { 0xA0, 0x60, 0x7C, 0x24, 0xE1, 0x4E, 0x8C, 0x22, 0x3D, 0xB0, 0xD7, 0x0B, 0x4D, 0x30, 0xEE, 0x88, 0x01, 0x4D, 0x60, 0x3F, 0x43, 0x7E, 0x9E, 0x02, 0xAA, 0x7D, 0xAF, 0xA3, 0xCD, 0xFB, 0xAD, 0x94 }, ++ { 0xDD, 0xBF, 0xEA, 0x75, 0xCC, 0x46, 0x78, 0x82, 0xEB, 0x34, 0x83, 0xCE, 0x5E, 0x2E, 0x75, 0x6A, 0x4F, 0x47, 0x01, 0xB7, 0x6B, 0x44, 0x55, 0x19, 0xE8, 0x9F, 0x22, 0xD6, 0x0F, 0xA8, 0x6E, 0x06 }, ++ { 0x0C, 0x31, 0x1F, 0x38, 0xC3, 0x5A, 0x4F, 0xB9, 0x0D, 0x65, 0x1C, 0x28, 0x9D, 0x48, 0x68, 0x56, 0xCD, 0x14, 0x13, 0xDF, 0x9B, 0x06, 0x77, 0xF5, 0x3E, 0xCE, 0x2C, 0xD9, 0xE4, 0x77, 0xC6, 0x0A }, ++ { 0x46, 0xA7, 0x3A, 0x8D, 0xD3, 0xE7, 0x0F, 0x59, 0xD3, 0x94, 0x2C, 0x01, 0xDF, 0x59, 0x9D, 0xEF, 0x78, 0x3C, 0x9D, 0xA8, 0x2F, 0xD8, 0x32, 0x22, 0xCD, 0x66, 0x2B, 0x53, 0xDC, 0xE7, 0xDB, 0xDF }, ++ { 0xAD, 0x03, 0x8F, 0xF9, 0xB1, 0x4D, 0xE8, 0x4A, 0x80, 0x1E, 0x4E, 0x62, 0x1C, 0xE5, 0xDF, 0x02, 0x9D, 0xD9, 0x35, 0x20, 0xD0, 0xC2, 0xFA, 0x38, 0xBF, 0xF1, 0x76, 0xA8, 0xB1, 0xD1, 0x69, 0x8C }, ++ { 0xAB, 0x70, 0xC5, 0xDF, 0xBD, 0x1E, 0xA8, 0x17, 0xFE, 0xD0, 0xCD, 0x06, 0x72, 0x93, 0xAB, 0xF3, 0x19, 0xE5, 0xD7, 0x90, 0x1C, 0x21, 0x41, 0xD5, 0xD9, 0x9B, 0x23, 0xF0, 0x3A, 0x38, 0xE7, 0x48 }, ++ { 0x1F, 0xFF, 0xDA, 0x67, 0x93, 0x2B, 0x73, 0xC8, 0xEC, 0xAF, 0x00, 0x9A, 0x34, 0x91, 0xA0, 0x26, 0x95, 0x3B, 0xAB, 0xFE, 0x1F, 0x66, 0x3B, 0x06, 0x97, 0xC3, 0xC4, 0xAE, 0x8B, 0x2E, 0x7D, 0xCB }, ++ { 0xB0, 0xD2, 0xCC, 0x19, 0x47, 0x2D, 0xD5, 0x7F, 0x2B, 0x17, 0xEF, 0xC0, 0x3C, 0x8D, 0x58, 0xC2, 0x28, 0x3D, 0xBB, 0x19, 0xDA, 0x57, 0x2F, 0x77, 0x55, 0x85, 0x5A, 0xA9, 0x79, 0x43, 0x17, 0xA0 }, ++ { 0xA0, 0xD1, 0x9A, 0x6E, 0xE3, 0x39, 0x79, 0xC3, 0x25, 0x51, 0x0E, 0x27, 0x66, 0x22, 0xDF, 0x41, 0xF7, 0x15, 0x83, 0xD0, 0x75, 0x01, 0xB8, 0x70, 0x71, 0x12, 0x9A, 0x0A, 0xD9, 0x47, 0x32, 0xA5 }, ++ { 0x72, 0x46, 0x42, 0xA7, 0x03, 0x2D, 0x10, 0x62, 0xB8, 0x9E, 0x52, 0xBE, 0xA3, 0x4B, 0x75, 0xDF, 0x7D, 0x8F, 0xE7, 0x72, 0xD9, 0xFE, 0x3C, 0x93, 0xDD, 0xF3, 0xC4, 0x54, 0x5A, 0xB5, 0xA9, 0x9B }, ++ { 0xAD, 0xE5, 0xEA, 0xA7, 0xE6, 0x1F, 0x67, 0x2D, 0x58, 0x7E, 0xA0, 0x3D, 0xAE, 0x7D, 0x7B, 0x55, 0x22, 0x9C, 0x01, 0xD0, 0x6B, 0xC0, 0xA5, 0x70, 0x14, 0x36, 0xCB, 0xD1, 0x83, 0x66, 0xA6, 0x26 }, ++ { 0x01, 0x3B, 0x31, 0xEB, 0xD2, 0x28, 0xFC, 0xDD, 0xA5, 0x1F, 0xAB, 0xB0, 0x3B, 0xB0, 0x2D, 0x60, 0xAC, 0x20, 0xCA, 0x21, 0x5A, 0xAF, 0xA8, 0x3B, 0xDD, 0x85, 0x5E, 0x37, 0x55, 0xA3, 0x5F, 0x0B }, ++ { 0x33, 0x2E, 0xD4, 0x0B, 0xB1, 0x0D, 0xDE, 0x3C, 0x95, 0x4A, 0x75, 0xD7, 0xB8, 0x99, 0x9D, 0x4B, 0x26, 0xA1, 0xC0, 0x63, 0xC1, 0xDC, 0x6E, 0x32, 0xC1, 0xD9, 0x1B, 0xAB, 0x7B, 0xBB, 0x7D, 0x16 }, ++ { 0xC7, 0xA1, 0x97, 0xB3, 0xA0, 0x5B, 0x56, 0x6B, 0xCC, 0x9F, 0xAC, 0xD2, 0x0E, 0x44, 0x1D, 0x6F, 0x6C, 0x28, 0x60, 0xAC, 0x96, 0x51, 0xCD, 0x51, 0xD6, 0xB9, 0xD2, 0xCD, 0xEE, 0xEA, 0x03, 0x90 }, ++ { 0xBD, 0x9C, 0xF6, 0x4E, 0xA8, 0x95, 0x3C, 0x03, 0x71, 0x08, 0xE6, 0xF6, 0x54, 0x91, 0x4F, 0x39, 0x58, 0xB6, 0x8E, 0x29, 0xC1, 0x67, 0x00, 0xDC, 0x18, 0x4D, 0x94, 0xA2, 0x17, 0x08, 0xFF, 0x60 }, ++ { 0x88, 0x35, 0xB0, 0xAC, 0x02, 0x11, 0x51, 0xDF, 0x71, 0x64, 0x74, 0xCE, 0x27, 0xCE, 0x4D, 0x3C, 0x15, 0xF0, 0xB2, 0xDA, 0xB4, 0x80, 0x03, 0xCF, 0x3F, 0x3E, 0xFD, 0x09, 0x45, 0x10, 0x6B, 0x9A }, ++ { 0x3B, 0xFE, 0xFA, 0x33, 0x01, 0xAA, 0x55, 0xC0, 0x80, 0x19, 0x0C, 0xFF, 0xDA, 0x8E, 0xAE, 0x51, 0xD9, 0xAF, 0x48, 0x8B, 0x4C, 0x1F, 0x24, 0xC3, 0xD9, 0xA7, 0x52, 0x42, 0xFD, 0x8E, 0xA0, 0x1D }, ++ { 0x08, 0x28, 0x4D, 0x14, 0x99, 0x3C, 0xD4, 0x7D, 0x53, 0xEB, 0xAE, 0xCF, 0x0D, 0xF0, 0x47, 0x8C, 0xC1, 0x82, 0xC8, 0x9C, 0x00, 0xE1, 0x85, 0x9C, 0x84, 0x85, 0x16, 0x86, 0xDD, 0xF2, 0xC1, 0xB7 }, ++ { 0x1E, 0xD7, 0xEF, 0x9F, 0x04, 0xC2, 0xAC, 0x8D, 0xB6, 0xA8, 0x64, 0xDB, 0x13, 0x10, 0x87, 0xF2, 0x70, 0x65, 0x09, 0x8E, 0x69, 0xC3, 0xFE, 0x78, 0x71, 0x8D, 0x9B, 0x94, 0x7F, 0x4A, 0x39, 0xD0 }, ++ { 0xC1, 0x61, 0xF2, 0xDC, 0xD5, 0x7E, 0x9C, 0x14, 0x39, 0xB3, 0x1A, 0x9D, 0xD4, 0x3D, 0x8F, 0x3D, 0x7D, 0xD8, 0xF0, 0xEB, 0x7C, 0xFA, 0xC6, 0xFB, 0x25, 0xA0, 0xF2, 0x8E, 0x30, 0x6F, 0x06, 0x61 }, ++ { 0xC0, 0x19, 0x69, 0xAD, 0x34, 0xC5, 0x2C, 0xAF, 0x3D, 0xC4, 0xD8, 0x0D, 0x19, 0x73, 0x5C, 0x29, 0x73, 0x1A, 0xC6, 0xE7, 0xA9, 0x20, 0x85, 0xAB, 0x92, 0x50, 0xC4, 0x8D, 0xEA, 0x48, 0xA3, 0xFC }, ++ { 0x17, 0x20, 0xB3, 0x65, 0x56, 0x19, 0xD2, 0xA5, 0x2B, 0x35, 0x21, 0xAE, 0x0E, 0x49, 0xE3, 0x45, 0xCB, 0x33, 0x89, 0xEB, 0xD6, 0x20, 0x8A, 0xCA, 0xF9, 0xF1, 0x3F, 0xDA, 0xCC, 0xA8, 0xBE, 0x49 }, ++ { 0x75, 0x62, 0x88, 0x36, 0x1C, 0x83, 0xE2, 0x4C, 0x61, 0x7C, 0xF9, 0x5C, 0x90, 0x5B, 0x22, 0xD0, 0x17, 0xCD, 0xC8, 0x6F, 0x0B, 0xF1, 0xD6, 0x58, 0xF4, 0x75, 0x6C, 0x73, 0x79, 0x87, 0x3B, 0x7F }, ++ { 0xE7, 0xD0, 0xED, 0xA3, 0x45, 0x26, 0x93, 0xB7, 0x52, 0xAB, 0xCD, 0xA1, 0xB5, 0x5E, 0x27, 0x6F, 0x82, 0x69, 0x8F, 0x5F, 0x16, 0x05, 0x40, 0x3E, 0xFF, 0x83, 0x0B, 0xEA, 0x00, 0x71, 0xA3, 0x94 }, ++ { 0x2C, 0x82, 0xEC, 0xAA, 0x6B, 0x84, 0x80, 0x3E, 0x04, 0x4A, 0xF6, 0x31, 0x18, 0xAF, 0xE5, 0x44, 0x68, 0x7C, 0xB6, 0xE6, 0xC7, 0xDF, 0x49, 0xED, 0x76, 0x2D, 0xFD, 0x7C, 0x86, 0x93, 0xA1, 0xBC }, ++ { 0x61, 0x36, 0xCB, 0xF4, 0xB4, 0x41, 0x05, 0x6F, 0xA1, 0xE2, 0x72, 0x24, 0x98, 0x12, 0x5D, 0x6D, 0xED, 0x45, 0xE1, 0x7B, 0x52, 0x14, 0x39, 0x59, 0xC7, 0xF4, 0xD4, 0xE3, 0x95, 0x21, 0x8A, 0xC2 }, ++ { 0x72, 0x1D, 0x32, 0x45, 0xAA, 0xFE, 0xF2, 0x7F, 0x6A, 0x62, 0x4F, 0x47, 0x95, 0x4B, 0x6C, 0x25, 0x50, 0x79, 0x52, 0x6F, 0xFA, 0x25, 0xE9, 0xFF, 0x77, 0xE5, 0xDC, 0xFF, 0x47, 0x3B, 0x15, 0x97 }, ++ { 0x9D, 0xD2, 0xFB, 0xD8, 0xCE, 0xF1, 0x6C, 0x35, 0x3C, 0x0A, 0xC2, 0x11, 0x91, 0xD5, 0x09, 0xEB, 0x28, 0xDD, 0x9E, 0x3E, 0x0D, 0x8C, 0xEA, 0x5D, 0x26, 0xCA, 0x83, 0x93, 0x93, 0x85, 0x1C, 0x3A }, ++ { 0xB2, 0x39, 0x4C, 0xEA, 0xCD, 0xEB, 0xF2, 0x1B, 0xF9, 0xDF, 0x2C, 0xED, 0x98, 0xE5, 0x8F, 0x1C, 0x3A, 0x4B, 0xBB, 0xFF, 0x66, 0x0D, 0xD9, 0x00, 0xF6, 0x22, 0x02, 0xD6, 0x78, 0x5C, 0xC4, 0x6E }, ++ { 0x57, 0x08, 0x9F, 0x22, 0x27, 0x49, 0xAD, 0x78, 0x71, 0x76, 0x5F, 0x06, 0x2B, 0x11, 0x4F, 0x43, 0xBA, 0x20, 0xEC, 0x56, 0x42, 0x2A, 0x8B, 0x1E, 0x3F, 0x87, 0x19, 0x2C, 0x0E, 0xA7, 0x18, 0xC6 }, ++ { 0xE4, 0x9A, 0x94, 0x59, 0x96, 0x1C, 0xD3, 0x3C, 0xDF, 0x4A, 0xAE, 0x1B, 0x10, 0x78, 0xA5, 0xDE, 0xA7, 0xC0, 0x40, 0xE0, 0xFE, 0xA3, 0x40, 0xC9, 0x3A, 0x72, 0x48, 0x72, 0xFC, 0x4A, 0xF8, 0x06 }, ++ { 0xED, 0xE6, 0x7F, 0x72, 0x0E, 0xFF, 0xD2, 0xCA, 0x9C, 0x88, 0x99, 0x41, 0x52, 0xD0, 0x20, 0x1D, 0xEE, 0x6B, 0x0A, 0x2D, 0x2C, 0x07, 0x7A, 0xCA, 0x6D, 0xAE, 0x29, 0xF7, 0x3F, 0x8B, 0x63, 0x09 }, ++ { 0xE0, 0xF4, 0x34, 0xBF, 0x22, 0xE3, 0x08, 0x80, 0x39, 0xC2, 0x1F, 0x71, 0x9F, 0xFC, 0x67, 0xF0, 0xF2, 0xCB, 0x5E, 0x98, 0xA7, 0xA0, 0x19, 0x4C, 0x76, 0xE9, 0x6B, 0xF4, 0xE8, 0xE1, 0x7E, 0x61 }, ++ { 0x27, 0x7C, 0x04, 0xE2, 0x85, 0x34, 0x84, 0xA4, 0xEB, 0xA9, 0x10, 0xAD, 0x33, 0x6D, 0x01, 0xB4, 0x77, 0xB6, 0x7C, 0xC2, 0x00, 0xC5, 0x9F, 0x3C, 0x8D, 0x77, 0xEE, 0xF8, 0x49, 0x4F, 0x29, 0xCD }, ++ { 0x15, 0x6D, 0x57, 0x47, 0xD0, 0xC9, 0x9C, 0x7F, 0x27, 0x09, 0x7D, 0x7B, 0x7E, 0x00, 0x2B, 0x2E, 0x18, 0x5C, 0xB7, 0x2D, 0x8D, 0xD7, 0xEB, 0x42, 0x4A, 0x03, 0x21, 0x52, 0x81, 0x61, 0x21, 0x9F }, ++ { 0x20, 0xDD, 0xD1, 0xED, 0x9B, 0x1C, 0xA8, 0x03, 0x94, 0x6D, 0x64, 0xA8, 0x3A, 0xE4, 0x65, 0x9D, 0xA6, 0x7F, 0xBA, 0x7A, 0x1A, 0x3E, 0xDD, 0xB1, 0xE1, 0x03, 0xC0, 0xF5, 0xE0, 0x3E, 0x3A, 0x2C }, ++ { 0xF0, 0xAF, 0x60, 0x4D, 0x3D, 0xAB, 0xBF, 0x9A, 0x0F, 0x2A, 0x7D, 0x3D, 0xDA, 0x6B, 0xD3, 0x8B, 0xBA, 0x72, 0xC6, 0xD0, 0x9B, 0xE4, 0x94, 0xFC, 0xEF, 0x71, 0x3F, 0xF1, 0x01, 0x89, 0xB6, 0xE6 }, ++ { 0x98, 0x02, 0xBB, 0x87, 0xDE, 0xF4, 0xCC, 0x10, 0xC4, 0xA5, 0xFD, 0x49, 0xAA, 0x58, 0xDF, 0xE2, 0xF3, 0xFD, 0xDB, 0x46, 0xB4, 0x70, 0x88, 0x14, 0xEA, 0xD8, 0x1D, 0x23, 0xBA, 0x95, 0x13, 0x9B }, ++ { 0x4F, 0x8C, 0xE1, 0xE5, 0x1D, 0x2F, 0xE7, 0xF2, 0x40, 0x43, 0xA9, 0x04, 0xD8, 0x98, 0xEB, 0xFC, 0x91, 0x97, 0x54, 0x18, 0x75, 0x34, 0x13, 0xAA, 0x09, 0x9B, 0x79, 0x5E, 0xCB, 0x35, 0xCE, 0xDB }, ++ { 0xBD, 0xDC, 0x65, 0x14, 0xD7, 0xEE, 0x6A, 0xCE, 0x0A, 0x4A, 0xC1, 0xD0, 0xE0, 0x68, 0x11, 0x22, 0x88, 0xCB, 0xCF, 0x56, 0x04, 0x54, 0x64, 0x27, 0x05, 0x63, 0x01, 0x77, 0xCB, 0xA6, 0x08, 0xBD }, ++ { 0xD6, 0x35, 0x99, 0x4F, 0x62, 0x91, 0x51, 0x7B, 0x02, 0x81, 0xFF, 0xDD, 0x49, 0x6A, 0xFA, 0x86, 0x27, 0x12, 0xE5, 0xB3, 0xC4, 0xE5, 0x2E, 0x4C, 0xD5, 0xFD, 0xAE, 0x8C, 0x0E, 0x72, 0xFB, 0x08 }, ++ { 0x87, 0x8D, 0x9C, 0xA6, 0x00, 0xCF, 0x87, 0xE7, 0x69, 0xCC, 0x30, 0x5C, 0x1B, 0x35, 0x25, 0x51, 0x86, 0x61, 0x5A, 0x73, 0xA0, 0xDA, 0x61, 0x3B, 0x5F, 0x1C, 0x98, 0xDB, 0xF8, 0x12, 0x83, 0xEA }, ++ { 0xA6, 0x4E, 0xBE, 0x5D, 0xC1, 0x85, 0xDE, 0x9F, 0xDD, 0xE7, 0x60, 0x7B, 0x69, 0x98, 0x70, 0x2E, 0xB2, 0x34, 0x56, 0x18, 0x49, 0x57, 0x30, 0x7D, 0x2F, 0xA7, 0x2E, 0x87, 0xA4, 0x77, 0x02, 0xD6 }, ++ { 0xCE, 0x50, 0xEA, 0xB7, 0xB5, 0xEB, 0x52, 0xBD, 0xC9, 0xAD, 0x8E, 0x5A, 0x48, 0x0A, 0xB7, 0x80, 0xCA, 0x93, 0x20, 0xE4, 0x43, 0x60, 0xB1, 0xFE, 0x37, 0xE0, 0x3F, 0x2F, 0x7A, 0xD7, 0xDE, 0x01 }, ++ { 0xEE, 0xDD, 0xB7, 0xC0, 0xDB, 0x6E, 0x30, 0xAB, 0xE6, 0x6D, 0x79, 0xE3, 0x27, 0x51, 0x1E, 0x61, 0xFC, 0xEB, 0xBC, 0x29, 0xF1, 0x59, 0xB4, 0x0A, 0x86, 0xB0, 0x46, 0xEC, 0xF0, 0x51, 0x38, 0x23 }, ++ { 0x78, 0x7F, 0xC9, 0x34, 0x40, 0xC1, 0xEC, 0x96, 0xB5, 0xAD, 0x01, 0xC1, 0x6C, 0xF7, 0x79, 0x16, 0xA1, 0x40, 0x5F, 0x94, 0x26, 0x35, 0x6E, 0xC9, 0x21, 0xD8, 0xDF, 0xF3, 0xEA, 0x63, 0xB7, 0xE0 }, ++ { 0x7F, 0x0D, 0x5E, 0xAB, 0x47, 0xEE, 0xFD, 0xA6, 0x96, 0xC0, 0xBF, 0x0F, 0xBF, 0x86, 0xAB, 0x21, 0x6F, 0xCE, 0x46, 0x1E, 0x93, 0x03, 0xAB, 0xA6, 0xAC, 0x37, 0x41, 0x20, 0xE8, 0x90, 0xE8, 0xDF }, ++ { 0xB6, 0x80, 0x04, 0xB4, 0x2F, 0x14, 0xAD, 0x02, 0x9F, 0x4C, 0x2E, 0x03, 0xB1, 0xD5, 0xEB, 0x76, 0xD5, 0x71, 0x60, 0xE2, 0x64, 0x76, 0xD2, 0x11, 0x31, 0xBE, 0xF2, 0x0A, 0xDA, 0x7D, 0x27, 0xF4 }, ++ { 0xB0, 0xC4, 0xEB, 0x18, 0xAE, 0x25, 0x0B, 0x51, 0xA4, 0x13, 0x82, 0xEA, 0xD9, 0x2D, 0x0D, 0xC7, 0x45, 0x5F, 0x93, 0x79, 0xFC, 0x98, 0x84, 0x42, 0x8E, 0x47, 0x70, 0x60, 0x8D, 0xB0, 0xFA, 0xEC }, ++ { 0xF9, 0x2B, 0x7A, 0x87, 0x0C, 0x05, 0x9F, 0x4D, 0x46, 0x46, 0x4C, 0x82, 0x4E, 0xC9, 0x63, 0x55, 0x14, 0x0B, 0xDC, 0xE6, 0x81, 0x32, 0x2C, 0xC3, 0xA9, 0x92, 0xFF, 0x10, 0x3E, 0x3F, 0xEA, 0x52 }, ++ { 0x53, 0x64, 0x31, 0x26, 0x14, 0x81, 0x33, 0x98, 0xCC, 0x52, 0x5D, 0x4C, 0x4E, 0x14, 0x6E, 0xDE, 0xB3, 0x71, 0x26, 0x5F, 0xBA, 0x19, 0x13, 0x3A, 0x2C, 0x3D, 0x21, 0x59, 0x29, 0x8A, 0x17, 0x42 }, ++ { 0xF6, 0x62, 0x0E, 0x68, 0xD3, 0x7F, 0xB2, 0xAF, 0x50, 0x00, 0xFC, 0x28, 0xE2, 0x3B, 0x83, 0x22, 0x97, 0xEC, 0xD8, 0xBC, 0xE9, 0x9E, 0x8B, 0xE4, 0xD0, 0x4E, 0x85, 0x30, 0x9E, 0x3D, 0x33, 0x74 }, ++ { 0x53, 0x16, 0xA2, 0x79, 0x69, 0xD7, 0xFE, 0x04, 0xFF, 0x27, 0xB2, 0x83, 0x96, 0x1B, 0xFF, 0xC3, 0xBF, 0x5D, 0xFB, 0x32, 0xFB, 0x6A, 0x89, 0xD1, 0x01, 0xC6, 0xC3, 0xB1, 0x93, 0x7C, 0x28, 0x71 }, ++ { 0x81, 0xD1, 0x66, 0x4F, 0xDF, 0x3C, 0xB3, 0x3C, 0x24, 0xEE, 0xBA, 0xC0, 0xBD, 0x64, 0x24, 0x4B, 0x77, 0xC4, 0xAB, 0xEA, 0x90, 0xBB, 0xE8, 0xB5, 0xEE, 0x0B, 0x2A, 0xAF, 0xCF, 0x2D, 0x6A, 0x53 }, ++ { 0x34, 0x57, 0x82, 0xF2, 0x95, 0xB0, 0x88, 0x03, 0x52, 0xE9, 0x24, 0xA0, 0x46, 0x7B, 0x5F, 0xBC, 0x3E, 0x8F, 0x3B, 0xFB, 0xC3, 0xC7, 0xE4, 0x8B, 0x67, 0x09, 0x1F, 0xB5, 0xE8, 0x0A, 0x94, 0x42 }, ++ { 0x79, 0x41, 0x11, 0xEA, 0x6C, 0xD6, 0x5E, 0x31, 0x1F, 0x74, 0xEE, 0x41, 0xD4, 0x76, 0xCB, 0x63, 0x2C, 0xE1, 0xE4, 0xB0, 0x51, 0xDC, 0x1D, 0x9E, 0x9D, 0x06, 0x1A, 0x19, 0xE1, 0xD0, 0xBB, 0x49 }, ++ { 0x2A, 0x85, 0xDA, 0xF6, 0x13, 0x88, 0x16, 0xB9, 0x9B, 0xF8, 0xD0, 0x8B, 0xA2, 0x11, 0x4B, 0x7A, 0xB0, 0x79, 0x75, 0xA7, 0x84, 0x20, 0xC1, 0xA3, 0xB0, 0x6A, 0x77, 0x7C, 0x22, 0xDD, 0x8B, 0xCB }, ++ { 0x89, 0xB0, 0xD5, 0xF2, 0x89, 0xEC, 0x16, 0x40, 0x1A, 0x06, 0x9A, 0x96, 0x0D, 0x0B, 0x09, 0x3E, 0x62, 0x5D, 0xA3, 0xCF, 0x41, 0xEE, 0x29, 0xB5, 0x9B, 0x93, 0x0C, 0x58, 0x20, 0x14, 0x54, 0x55 }, ++ { 0xD0, 0xFD, 0xCB, 0x54, 0x39, 0x43, 0xFC, 0x27, 0xD2, 0x08, 0x64, 0xF5, 0x21, 0x81, 0x47, 0x1B, 0x94, 0x2C, 0xC7, 0x7C, 0xA6, 0x75, 0xBC, 0xB3, 0x0D, 0xF3, 0x1D, 0x35, 0x8E, 0xF7, 0xB1, 0xEB }, ++ { 0xB1, 0x7E, 0xA8, 0xD7, 0x70, 0x63, 0xC7, 0x09, 0xD4, 0xDC, 0x6B, 0x87, 0x94, 0x13, 0xC3, 0x43, 0xE3, 0x79, 0x0E, 0x9E, 0x62, 0xCA, 0x85, 0xB7, 0x90, 0x0B, 0x08, 0x6F, 0x6B, 0x75, 0xC6, 0x72 }, ++ { 0xE7, 0x1A, 0x3E, 0x2C, 0x27, 0x4D, 0xB8, 0x42, 0xD9, 0x21, 0x14, 0xF2, 0x17, 0xE2, 0xC0, 0xEA, 0xC8, 0xB4, 0x50, 0x93, 0xFD, 0xFD, 0x9D, 0xF4, 0xCA, 0x71, 0x62, 0x39, 0x48, 0x62, 0xD5, 0x01 }, ++ { 0xC0, 0x47, 0x67, 0x59, 0xAB, 0x7A, 0xA3, 0x33, 0x23, 0x4F, 0x6B, 0x44, 0xF5, 0xFD, 0x85, 0x83, 0x90, 0xEC, 0x23, 0x69, 0x4C, 0x62, 0x2C, 0xB9, 0x86, 0xE7, 0x69, 0xC7, 0x8E, 0xDD, 0x73, 0x3E }, ++ { 0x9A, 0xB8, 0xEA, 0xBB, 0x14, 0x16, 0x43, 0x4D, 0x85, 0x39, 0x13, 0x41, 0xD5, 0x69, 0x93, 0xC5, 0x54, 0x58, 0x16, 0x7D, 0x44, 0x18, 0xB1, 0x9A, 0x0F, 0x2A, 0xD8, 0xB7, 0x9A, 0x83, 0xA7, 0x5B }, ++ { 0x79, 0x92, 0xD0, 0xBB, 0xB1, 0x5E, 0x23, 0x82, 0x6F, 0x44, 0x3E, 0x00, 0x50, 0x5D, 0x68, 0xD3, 0xED, 0x73, 0x72, 0x99, 0x5A, 0x5C, 0x3E, 0x49, 0x86, 0x54, 0x10, 0x2F, 0xBC, 0xD0, 0x96, 0x4E }, ++ { 0xC0, 0x21, 0xB3, 0x00, 0x85, 0x15, 0x14, 0x35, 0xDF, 0x33, 0xB0, 0x07, 0xCC, 0xEC, 0xC6, 0x9D, 0xF1, 0x26, 0x9F, 0x39, 0xBA, 0x25, 0x09, 0x2B, 0xED, 0x59, 0xD9, 0x32, 0xAC, 0x0F, 0xDC, 0x28 }, ++ { 0x91, 0xA2, 0x5E, 0xC0, 0xEC, 0x0D, 0x9A, 0x56, 0x7F, 0x89, 0xC4, 0xBF, 0xE1, 0xA6, 0x5A, 0x0E, 0x43, 0x2D, 0x07, 0x06, 0x4B, 0x41, 0x90, 0xE2, 0x7D, 0xFB, 0x81, 0x90, 0x1F, 0xD3, 0x13, 0x9B }, ++ { 0x59, 0x50, 0xD3, 0x9A, 0x23, 0xE1, 0x54, 0x5F, 0x30, 0x12, 0x70, 0xAA, 0x1A, 0x12, 0xF2, 0xE6, 0xC4, 0x53, 0x77, 0x6E, 0x4D, 0x63, 0x55, 0xDE, 0x42, 0x5C, 0xC1, 0x53, 0xF9, 0x81, 0x88, 0x67 }, ++ { 0xD7, 0x9F, 0x14, 0x72, 0x0C, 0x61, 0x0A, 0xF1, 0x79, 0xA3, 0x76, 0x5D, 0x4B, 0x7C, 0x09, 0x68, 0xF9, 0x77, 0x96, 0x2D, 0xBF, 0x65, 0x5B, 0x52, 0x12, 0x72, 0xB6, 0xF1, 0xE1, 0x94, 0x48, 0x8E }, ++ { 0xE9, 0x53, 0x1B, 0xFC, 0x8B, 0x02, 0x99, 0x5A, 0xEA, 0xA7, 0x5B, 0xA2, 0x70, 0x31, 0xFA, 0xDB, 0xCB, 0xF4, 0xA0, 0xDA, 0xB8, 0x96, 0x1D, 0x92, 0x96, 0xCD, 0x7E, 0x84, 0xD2, 0x5D, 0x60, 0x06 }, ++ { 0x34, 0xE9, 0xC2, 0x6A, 0x01, 0xD7, 0xF1, 0x61, 0x81, 0xB4, 0x54, 0xA9, 0xD1, 0x62, 0x3C, 0x23, 0x3C, 0xB9, 0x9D, 0x31, 0xC6, 0x94, 0x65, 0x6E, 0x94, 0x13, 0xAC, 0xA3, 0xE9, 0x18, 0x69, 0x2F }, ++ { 0xD9, 0xD7, 0x42, 0x2F, 0x43, 0x7B, 0xD4, 0x39, 0xDD, 0xD4, 0xD8, 0x83, 0xDA, 0xE2, 0xA0, 0x83, 0x50, 0x17, 0x34, 0x14, 0xBE, 0x78, 0x15, 0x51, 0x33, 0xFF, 0xF1, 0x96, 0x4C, 0x3D, 0x79, 0x72 }, ++ { 0x4A, 0xEE, 0x0C, 0x7A, 0xAF, 0x07, 0x54, 0x14, 0xFF, 0x17, 0x93, 0xEA, 0xD7, 0xEA, 0xCA, 0x60, 0x17, 0x75, 0xC6, 0x15, 0xDB, 0xD6, 0x0B, 0x64, 0x0B, 0x0A, 0x9F, 0x0C, 0xE5, 0x05, 0xD4, 0x35 }, ++ { 0x6B, 0xFD, 0xD1, 0x54, 0x59, 0xC8, 0x3B, 0x99, 0xF0, 0x96, 0xBF, 0xB4, 0x9E, 0xE8, 0x7B, 0x06, 0x3D, 0x69, 0xC1, 0x97, 0x4C, 0x69, 0x28, 0xAC, 0xFC, 0xFB, 0x40, 0x99, 0xF8, 0xC4, 0xEF, 0x67 }, ++ { 0x9F, 0xD1, 0xC4, 0x08, 0xFD, 0x75, 0xC3, 0x36, 0x19, 0x3A, 0x2A, 0x14, 0xD9, 0x4F, 0x6A, 0xF5, 0xAD, 0xF0, 0x50, 0xB8, 0x03, 0x87, 0xB4, 0xB0, 0x10, 0xFB, 0x29, 0xF4, 0xCC, 0x72, 0x70, 0x7C }, ++ { 0x13, 0xC8, 0x84, 0x80, 0xA5, 0xD0, 0x0D, 0x6C, 0x8C, 0x7A, 0xD2, 0x11, 0x0D, 0x76, 0xA8, 0x2D, 0x9B, 0x70, 0xF4, 0xFA, 0x66, 0x96, 0xD4, 0xE5, 0xDD, 0x42, 0xA0, 0x66, 0xDC, 0xAF, 0x99, 0x20 }, ++ { 0x82, 0x0E, 0x72, 0x5E, 0xE2, 0x5F, 0xE8, 0xFD, 0x3A, 0x8D, 0x5A, 0xBE, 0x4C, 0x46, 0xC3, 0xBA, 0x88, 0x9D, 0xE6, 0xFA, 0x91, 0x91, 0xAA, 0x22, 0xBA, 0x67, 0xD5, 0x70, 0x54, 0x21, 0x54, 0x2B }, ++ { 0x32, 0xD9, 0x3A, 0x0E, 0xB0, 0x2F, 0x42, 0xFB, 0xBC, 0xAF, 0x2B, 0xAD, 0x00, 0x85, 0xB2, 0x82, 0xE4, 0x60, 0x46, 0xA4, 0xDF, 0x7A, 0xD1, 0x06, 0x57, 0xC9, 0xD6, 0x47, 0x63, 0x75, 0xB9, 0x3E }, ++ { 0xAD, 0xC5, 0x18, 0x79, 0x05, 0xB1, 0x66, 0x9C, 0xD8, 0xEC, 0x9C, 0x72, 0x1E, 0x19, 0x53, 0x78, 0x6B, 0x9D, 0x89, 0xA9, 0xBA, 0xE3, 0x07, 0x80, 0xF1, 0xE1, 0xEA, 0xB2, 0x4A, 0x00, 0x52, 0x3C }, ++ { 0xE9, 0x07, 0x56, 0xFF, 0x7F, 0x9A, 0xD8, 0x10, 0xB2, 0x39, 0xA1, 0x0C, 0xED, 0x2C, 0xF9, 0xB2, 0x28, 0x43, 0x54, 0xC1, 0xF8, 0xC7, 0xE0, 0xAC, 0xCC, 0x24, 0x61, 0xDC, 0x79, 0x6D, 0x6E, 0x89 }, ++ { 0x12, 0x51, 0xF7, 0x6E, 0x56, 0x97, 0x84, 0x81, 0x87, 0x53, 0x59, 0x80, 0x1D, 0xB5, 0x89, 0xA0, 0xB2, 0x2F, 0x86, 0xD8, 0xD6, 0x34, 0xDC, 0x04, 0x50, 0x6F, 0x32, 0x2E, 0xD7, 0x8F, 0x17, 0xE8 }, ++ { 0x3A, 0xFA, 0x89, 0x9F, 0xD9, 0x80, 0xE7, 0x3E, 0xCB, 0x7F, 0x4D, 0x8B, 0x8F, 0x29, 0x1D, 0xC9, 0xAF, 0x79, 0x6B, 0xC6, 0x5D, 0x27, 0xF9, 0x74, 0xC6, 0xF1, 0x93, 0xC9, 0x19, 0x1A, 0x09, 0xFD }, ++ { 0xAA, 0x30, 0x5B, 0xE2, 0x6E, 0x5D, 0xED, 0xDC, 0x3C, 0x10, 0x10, 0xCB, 0xC2, 0x13, 0xF9, 0x5F, 0x05, 0x1C, 0x78, 0x5C, 0x5B, 0x43, 0x1E, 0x6A, 0x7C, 0xD0, 0x48, 0xF1, 0x61, 0x78, 0x75, 0x28 }, ++ { 0x8E, 0xA1, 0x88, 0x4F, 0xF3, 0x2E, 0x9D, 0x10, 0xF0, 0x39, 0xB4, 0x07, 0xD0, 0xD4, 0x4E, 0x7E, 0x67, 0x0A, 0xBD, 0x88, 0x4A, 0xEE, 0xE0, 0xFB, 0x75, 0x7A, 0xE9, 0x4E, 0xAA, 0x97, 0x37, 0x3D }, ++ { 0xD4, 0x82, 0xB2, 0x15, 0x5D, 0x4D, 0xEC, 0x6B, 0x47, 0x36, 0xA1, 0xF1, 0x61, 0x7B, 0x53, 0xAA, 0xA3, 0x73, 0x10, 0x27, 0x7D, 0x3F, 0xEF, 0x0C, 0x37, 0xAD, 0x41, 0x76, 0x8F, 0xC2, 0x35, 0xB4 }, ++ { 0x4D, 0x41, 0x39, 0x71, 0x38, 0x7E, 0x7A, 0x88, 0x98, 0xA8, 0xDC, 0x2A, 0x27, 0x50, 0x07, 0x78, 0x53, 0x9E, 0xA2, 0x14, 0xA2, 0xDF, 0xE9, 0xB3, 0xD7, 0xE8, 0xEB, 0xDC, 0xE5, 0xCF, 0x3D, 0xB3 }, ++ { 0x69, 0x6E, 0x5D, 0x46, 0xE6, 0xC5, 0x7E, 0x87, 0x96, 0xE4, 0x73, 0x5D, 0x08, 0x91, 0x6E, 0x0B, 0x79, 0x29, 0xB3, 0xCF, 0x29, 0x8C, 0x29, 0x6D, 0x22, 0xE9, 0xD3, 0x01, 0x96, 0x53, 0x37, 0x1C }, ++ { 0x1F, 0x56, 0x47, 0xC1, 0xD3, 0xB0, 0x88, 0x22, 0x88, 0x85, 0x86, 0x5C, 0x89, 0x40, 0x90, 0x8B, 0xF4, 0x0D, 0x1A, 0x82, 0x72, 0x82, 0x19, 0x73, 0xB1, 0x60, 0x00, 0x8E, 0x7A, 0x3C, 0xE2, 0xEB }, ++ { 0xB6, 0xE7, 0x6C, 0x33, 0x0F, 0x02, 0x1A, 0x5B, 0xDA, 0x65, 0x87, 0x50, 0x10, 0xB0, 0xED, 0xF0, 0x91, 0x26, 0xC0, 0xF5, 0x10, 0xEA, 0x84, 0x90, 0x48, 0x19, 0x20, 0x03, 0xAE, 0xF4, 0xC6, 0x1C }, ++ { 0x3C, 0xD9, 0x52, 0xA0, 0xBE, 0xAD, 0xA4, 0x1A, 0xBB, 0x42, 0x4C, 0xE4, 0x7F, 0x94, 0xB4, 0x2B, 0xE6, 0x4E, 0x1F, 0xFB, 0x0F, 0xD0, 0x78, 0x22, 0x76, 0x80, 0x79, 0x46, 0xD0, 0xD0, 0xBC, 0x55 }, ++ { 0x98, 0xD9, 0x26, 0x77, 0x43, 0x9B, 0x41, 0xB7, 0xBB, 0x51, 0x33, 0x12, 0xAF, 0xB9, 0x2B, 0xCC, 0x8E, 0xE9, 0x68, 0xB2, 0xE3, 0xB2, 0x38, 0xCE, 0xCB, 0x9B, 0x0F, 0x34, 0xC9, 0xBB, 0x63, 0xD0 }, ++ { 0xEC, 0xBC, 0xA2, 0xCF, 0x08, 0xAE, 0x57, 0xD5, 0x17, 0xAD, 0x16, 0x15, 0x8A, 0x32, 0xBF, 0xA7, 0xDC, 0x03, 0x82, 0xEA, 0xED, 0xA1, 0x28, 0xE9, 0x18, 0x86, 0x73, 0x4C, 0x24, 0xA0, 0xB2, 0x9D }, ++ { 0x94, 0x2C, 0xC7, 0xC0, 0xB5, 0x2E, 0x2B, 0x16, 0xA4, 0xB8, 0x9F, 0xA4, 0xFC, 0x7E, 0x0B, 0xF6, 0x09, 0xE2, 0x9A, 0x08, 0xC1, 0xA8, 0x54, 0x34, 0x52, 0xB7, 0x7C, 0x7B, 0xFD, 0x11, 0xBB, 0x28 }, ++ { 0x8A, 0x06, 0x5D, 0x8B, 0x61, 0xA0, 0xDF, 0xFB, 0x17, 0x0D, 0x56, 0x27, 0x73, 0x5A, 0x76, 0xB0, 0xE9, 0x50, 0x60, 0x37, 0x80, 0x8C, 0xBA, 0x16, 0xC3, 0x45, 0x00, 0x7C, 0x9F, 0x79, 0xCF, 0x8F }, ++ { 0x1B, 0x9F, 0xA1, 0x97, 0x14, 0x65, 0x9C, 0x78, 0xFF, 0x41, 0x38, 0x71, 0x84, 0x92, 0x15, 0x36, 0x10, 0x29, 0xAC, 0x80, 0x2B, 0x1C, 0xBC, 0xD5, 0x4E, 0x40, 0x8B, 0xD8, 0x72, 0x87, 0xF8, 0x1F }, ++ { 0x8D, 0xAB, 0x07, 0x1B, 0xCD, 0x6C, 0x72, 0x92, 0xA9, 0xEF, 0x72, 0x7B, 0x4A, 0xE0, 0xD8, 0x67, 0x13, 0x30, 0x1D, 0xA8, 0x61, 0x8D, 0x9A, 0x48, 0xAD, 0xCE, 0x55, 0xF3, 0x03, 0xA8, 0x69, 0xA1 }, ++ { 0x82, 0x53, 0xE3, 0xE7, 0xC7, 0xB6, 0x84, 0xB9, 0xCB, 0x2B, 0xEB, 0x01, 0x4C, 0xE3, 0x30, 0xFF, 0x3D, 0x99, 0xD1, 0x7A, 0xBB, 0xDB, 0xAB, 0xE4, 0xF4, 0xD6, 0x74, 0xDE, 0xD5, 0x3F, 0xFC, 0x6B }, ++ { 0xF1, 0x95, 0xF3, 0x21, 0xE9, 0xE3, 0xD6, 0xBD, 0x7D, 0x07, 0x45, 0x04, 0xDD, 0x2A, 0xB0, 0xE6, 0x24, 0x1F, 0x92, 0xE7, 0x84, 0xB1, 0xAA, 0x27, 0x1F, 0xF6, 0x48, 0xB1, 0xCA, 0xB6, 0xD7, 0xF6 }, ++ { 0x27, 0xE4, 0xCC, 0x72, 0x09, 0x0F, 0x24, 0x12, 0x66, 0x47, 0x6A, 0x7C, 0x09, 0x49, 0x5F, 0x2D, 0xB1, 0x53, 0xD5, 0xBC, 0xBD, 0x76, 0x19, 0x03, 0xEF, 0x79, 0x27, 0x5E, 0xC5, 0x6B, 0x2E, 0xD8 }, ++ { 0x89, 0x9C, 0x24, 0x05, 0x78, 0x8E, 0x25, 0xB9, 0x9A, 0x18, 0x46, 0x35, 0x5E, 0x64, 0x6D, 0x77, 0xCF, 0x40, 0x00, 0x83, 0x41, 0x5F, 0x7D, 0xC5, 0xAF, 0xE6, 0x9D, 0x6E, 0x17, 0xC0, 0x00, 0x23 }, ++ { 0xA5, 0x9B, 0x78, 0xC4, 0x90, 0x57, 0x44, 0x07, 0x6B, 0xFE, 0xE8, 0x94, 0xDE, 0x70, 0x7D, 0x4F, 0x12, 0x0B, 0x5C, 0x68, 0x93, 0xEA, 0x04, 0x00, 0x29, 0x7D, 0x0B, 0xB8, 0x34, 0x72, 0x76, 0x32 }, ++ { 0x59, 0xDC, 0x78, 0xB1, 0x05, 0x64, 0x97, 0x07, 0xA2, 0xBB, 0x44, 0x19, 0xC4, 0x8F, 0x00, 0x54, 0x00, 0xD3, 0x97, 0x3D, 0xE3, 0x73, 0x66, 0x10, 0x23, 0x04, 0x35, 0xB1, 0x04, 0x24, 0xB2, 0x4F }, ++ { 0xC0, 0x14, 0x9D, 0x1D, 0x7E, 0x7A, 0x63, 0x53, 0xA6, 0xD9, 0x06, 0xEF, 0xE7, 0x28, 0xF2, 0xF3, 0x29, 0xFE, 0x14, 0xA4, 0x14, 0x9A, 0x3E, 0xA7, 0x76, 0x09, 0xBC, 0x42, 0xB9, 0x75, 0xDD, 0xFA }, ++ { 0xA3, 0x2F, 0x24, 0x14, 0x74, 0xA6, 0xC1, 0x69, 0x32, 0xE9, 0x24, 0x3B, 0xE0, 0xCF, 0x09, 0xBC, 0xDC, 0x7E, 0x0C, 0xA0, 0xE7, 0xA6, 0xA1, 0xB9, 0xB1, 0xA0, 0xF0, 0x1E, 0x41, 0x50, 0x23, 0x77 }, ++ { 0xB2, 0x39, 0xB2, 0xE4, 0xF8, 0x18, 0x41, 0x36, 0x1C, 0x13, 0x39, 0xF6, 0x8E, 0x2C, 0x35, 0x9F, 0x92, 0x9A, 0xF9, 0xAD, 0x9F, 0x34, 0xE0, 0x1A, 0xAB, 0x46, 0x31, 0xAD, 0x6D, 0x55, 0x00, 0xB0 }, ++ { 0x85, 0xFB, 0x41, 0x9C, 0x70, 0x02, 0xA3, 0xE0, 0xB4, 0xB6, 0xEA, 0x09, 0x3B, 0x4C, 0x1A, 0xC6, 0x93, 0x66, 0x45, 0xB6, 0x5D, 0xAC, 0x5A, 0xC1, 0x5A, 0x85, 0x28, 0xB7, 0xB9, 0x4C, 0x17, 0x54 }, ++ { 0x96, 0x19, 0x72, 0x06, 0x25, 0xF1, 0x90, 0xB9, 0x3A, 0x3F, 0xAD, 0x18, 0x6A, 0xB3, 0x14, 0x18, 0x96, 0x33, 0xC0, 0xD3, 0xA0, 0x1E, 0x6F, 0x9B, 0xC8, 0xC4, 0xA8, 0xF8, 0x2F, 0x38, 0x3D, 0xBF }, ++ { 0x7D, 0x62, 0x0D, 0x90, 0xFE, 0x69, 0xFA, 0x46, 0x9A, 0x65, 0x38, 0x38, 0x89, 0x70, 0xA1, 0xAA, 0x09, 0xBB, 0x48, 0xA2, 0xD5, 0x9B, 0x34, 0x7B, 0x97, 0xE8, 0xCE, 0x71, 0xF4, 0x8C, 0x7F, 0x46 }, ++ { 0x29, 0x43, 0x83, 0x56, 0x85, 0x96, 0xFB, 0x37, 0xC7, 0x5B, 0xBA, 0xCD, 0x97, 0x9C, 0x5F, 0xF6, 0xF2, 0x0A, 0x55, 0x6B, 0xF8, 0x87, 0x9C, 0xC7, 0x29, 0x24, 0x85, 0x5D, 0xF9, 0xB8, 0x24, 0x0E }, ++ { 0x16, 0xB1, 0x8A, 0xB3, 0x14, 0x35, 0x9C, 0x2B, 0x83, 0x3C, 0x1C, 0x69, 0x86, 0xD4, 0x8C, 0x55, 0xA9, 0xFC, 0x97, 0xCD, 0xE9, 0xA3, 0xC1, 0xF1, 0x0A, 0x31, 0x77, 0x14, 0x0F, 0x73, 0xF7, 0x38 }, ++ { 0x8C, 0xBB, 0xDD, 0x14, 0xBC, 0x33, 0xF0, 0x4C, 0xF4, 0x58, 0x13, 0xE4, 0xA1, 0x53, 0xA2, 0x73, 0xD3, 0x6A, 0xDA, 0xD5, 0xCE, 0x71, 0xF4, 0x99, 0xEE, 0xB8, 0x7F, 0xB8, 0xAC, 0x63, 0xB7, 0x29 }, ++ { 0x69, 0xC9, 0xA4, 0x98, 0xDB, 0x17, 0x4E, 0xCA, 0xEF, 0xCC, 0x5A, 0x3A, 0xC9, 0xFD, 0xED, 0xF0, 0xF8, 0x13, 0xA5, 0xBE, 0xC7, 0x27, 0xF1, 0xE7, 0x75, 0xBA, 0xBD, 0xEC, 0x77, 0x18, 0x81, 0x6E }, ++ { 0xB4, 0x62, 0xC3, 0xBE, 0x40, 0x44, 0x8F, 0x1D, 0x4F, 0x80, 0x62, 0x62, 0x54, 0xE5, 0x35, 0xB0, 0x8B, 0xC9, 0xCD, 0xCF, 0xF5, 0x99, 0xA7, 0x68, 0x57, 0x8D, 0x4B, 0x28, 0x81, 0xA8, 0xE3, 0xF0 }, ++ { 0x55, 0x3E, 0x9D, 0x9C, 0x5F, 0x36, 0x0A, 0xC0, 0xB7, 0x4A, 0x7D, 0x44, 0xE5, 0xA3, 0x91, 0xDA, 0xD4, 0xCE, 0xD0, 0x3E, 0x0C, 0x24, 0x18, 0x3B, 0x7E, 0x8E, 0xCA, 0xBD, 0xF1, 0x71, 0x5A, 0x64 }, ++ { 0x7A, 0x7C, 0x55, 0xA5, 0x6F, 0xA9, 0xAE, 0x51, 0xE6, 0x55, 0xE0, 0x19, 0x75, 0xD8, 0xA6, 0xFF, 0x4A, 0xE9, 0xE4, 0xB4, 0x86, 0xFC, 0xBE, 0x4E, 0xAC, 0x04, 0x45, 0x88, 0xF2, 0x45, 0xEB, 0xEA }, ++ { 0x2A, 0xFD, 0xF3, 0xC8, 0x2A, 0xBC, 0x48, 0x67, 0xF5, 0xDE, 0x11, 0x12, 0x86, 0xC2, 0xB3, 0xBE, 0x7D, 0x6E, 0x48, 0x65, 0x7B, 0xA9, 0x23, 0xCF, 0xBF, 0x10, 0x1A, 0x6D, 0xFC, 0xF9, 0xDB, 0x9A }, ++ { 0x41, 0x03, 0x7D, 0x2E, 0xDC, 0xDC, 0xE0, 0xC4, 0x9B, 0x7F, 0xB4, 0xA6, 0xAA, 0x09, 0x99, 0xCA, 0x66, 0x97, 0x6C, 0x74, 0x83, 0xAF, 0xE6, 0x31, 0xD4, 0xED, 0xA2, 0x83, 0x14, 0x4F, 0x6D, 0xFC }, ++ { 0xC4, 0x46, 0x6F, 0x84, 0x97, 0xCA, 0x2E, 0xEB, 0x45, 0x83, 0xA0, 0xB0, 0x8E, 0x9D, 0x9A, 0xC7, 0x43, 0x95, 0x70, 0x9F, 0xDA, 0x10, 0x9D, 0x24, 0xF2, 0xE4, 0x46, 0x21, 0x96, 0x77, 0x9C, 0x5D }, ++ { 0x75, 0xF6, 0x09, 0x33, 0x8A, 0xA6, 0x7D, 0x96, 0x9A, 0x2A, 0xE2, 0xA2, 0x36, 0x2B, 0x2D, 0xA9, 0xD7, 0x7C, 0x69, 0x5D, 0xFD, 0x1D, 0xF7, 0x22, 0x4A, 0x69, 0x01, 0xDB, 0x93, 0x2C, 0x33, 0x64 }, ++ { 0x68, 0x60, 0x6C, 0xEB, 0x98, 0x9D, 0x54, 0x88, 0xFC, 0x7C, 0xF6, 0x49, 0xF3, 0xD7, 0xC2, 0x72, 0xEF, 0x05, 0x5D, 0xA1, 0xA9, 0x3F, 0xAE, 0xCD, 0x55, 0xFE, 0x06, 0xF6, 0x96, 0x70, 0x98, 0xCA }, ++ { 0x44, 0x34, 0x6B, 0xDE, 0xB7, 0xE0, 0x52, 0xF6, 0x25, 0x50, 0x48, 0xF0, 0xD9, 0xB4, 0x2C, 0x42, 0x5B, 0xAB, 0x9C, 0x3D, 0xD2, 0x41, 0x68, 0x21, 0x2C, 0x3E, 0xCF, 0x1E, 0xBF, 0x34, 0xE6, 0xAE }, ++ { 0x8E, 0x9C, 0xF6, 0xE1, 0xF3, 0x66, 0x47, 0x1F, 0x2A, 0xC7, 0xD2, 0xEE, 0x9B, 0x5E, 0x62, 0x66, 0xFD, 0xA7, 0x1F, 0x8F, 0x2E, 0x41, 0x09, 0xF2, 0x23, 0x7E, 0xD5, 0xF8, 0x81, 0x3F, 0xC7, 0x18 }, ++ { 0x84, 0xBB, 0xEB, 0x84, 0x06, 0xD2, 0x50, 0x95, 0x1F, 0x8C, 0x1B, 0x3E, 0x86, 0xA7, 0xC0, 0x10, 0x08, 0x29, 0x21, 0x83, 0x3D, 0xFD, 0x95, 0x55, 0xA2, 0xF9, 0x09, 0xB1, 0x08, 0x6E, 0xB4, 0xB8 }, ++ { 0xEE, 0x66, 0x6F, 0x3E, 0xEF, 0x0F, 0x7E, 0x2A, 0x9C, 0x22, 0x29, 0x58, 0xC9, 0x7E, 0xAF, 0x35, 0xF5, 0x1C, 0xED, 0x39, 0x3D, 0x71, 0x44, 0x85, 0xAB, 0x09, 0xA0, 0x69, 0x34, 0x0F, 0xDF, 0x88 }, ++ { 0xC1, 0x53, 0xD3, 0x4A, 0x65, 0xC4, 0x7B, 0x4A, 0x62, 0xC5, 0xCA, 0xCF, 0x24, 0x01, 0x09, 0x75, 0xD0, 0x35, 0x6B, 0x2F, 0x32, 0xC8, 0xF5, 0xDA, 0x53, 0x0D, 0x33, 0x88, 0x16, 0xAD, 0x5D, 0xE6 }, ++ { 0x9F, 0xC5, 0x45, 0x01, 0x09, 0xE1, 0xB7, 0x79, 0xF6, 0xC7, 0xAE, 0x79, 0xD5, 0x6C, 0x27, 0x63, 0x5C, 0x8D, 0xD4, 0x26, 0xC5, 0xA9, 0xD5, 0x4E, 0x25, 0x78, 0xDB, 0x98, 0x9B, 0x8C, 0x3B, 0x4E }, ++ { 0xD1, 0x2B, 0xF3, 0x73, 0x2E, 0xF4, 0xAF, 0x5C, 0x22, 0xFA, 0x90, 0x35, 0x6A, 0xF8, 0xFC, 0x50, 0xFC, 0xB4, 0x0F, 0x8F, 0x2E, 0xA5, 0xC8, 0x59, 0x47, 0x37, 0xA3, 0xB3, 0xD5, 0xAB, 0xDB, 0xD7 }, ++ { 0x11, 0x03, 0x0B, 0x92, 0x89, 0xBB, 0xA5, 0xAF, 0x65, 0x26, 0x06, 0x72, 0xAB, 0x6F, 0xEE, 0x88, 0xB8, 0x74, 0x20, 0xAC, 0xEF, 0x4A, 0x17, 0x89, 0xA2, 0x07, 0x3B, 0x7E, 0xC2, 0xF2, 0xA0, 0x9E }, ++ { 0x69, 0xCB, 0x19, 0x2B, 0x84, 0x44, 0x00, 0x5C, 0x8C, 0x0C, 0xEB, 0x12, 0xC8, 0x46, 0x86, 0x07, 0x68, 0x18, 0x8C, 0xDA, 0x0A, 0xEC, 0x27, 0xA9, 0xC8, 0xA5, 0x5C, 0xDE, 0xE2, 0x12, 0x36, 0x32 }, ++ { 0xDB, 0x44, 0x4C, 0x15, 0x59, 0x7B, 0x5F, 0x1A, 0x03, 0xD1, 0xF9, 0xED, 0xD1, 0x6E, 0x4A, 0x9F, 0x43, 0xA6, 0x67, 0xCC, 0x27, 0x51, 0x75, 0xDF, 0xA2, 0xB7, 0x04, 0xE3, 0xBB, 0x1A, 0x9B, 0x83 }, ++ { 0x3F, 0xB7, 0x35, 0x06, 0x1A, 0xBC, 0x51, 0x9D, 0xFE, 0x97, 0x9E, 0x54, 0xC1, 0xEE, 0x5B, 0xFA, 0xD0, 0xA9, 0xD8, 0x58, 0xB3, 0x31, 0x5B, 0xAD, 0x34, 0xBD, 0xE9, 0x99, 0xEF, 0xD7, 0x24, 0xDD } ++}; ++ ++bool blake2s_selftest(void) ++{ ++ u8 key[BLAKE2S_KEYBYTES]; ++ u8 buf[ARRAY_SIZE(blake2s_testvecs)]; ++ u8 hash[BLAKE2S_OUTBYTES]; ++ size_t i; ++ bool success = true; ++ ++ for (i = 0; i < BLAKE2S_KEYBYTES; ++i) ++ key[i] = (u8)i; ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i) ++ buf[i] = (u8)i; ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_keyed_testvecs); ++i) { ++ blake2s(hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES); ++ if (memcmp(hash, blake2s_keyed_testvecs[i], BLAKE2S_OUTBYTES)) { ++ pr_info("blake2s keyed self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i) { ++ blake2s(hash, buf, NULL, BLAKE2S_OUTBYTES, i, 0); ++ if (memcmp(hash, blake2s_testvecs[i], BLAKE2S_OUTBYTES)) { ++ pr_info("blake2s unkeyed self-test %zu: FAIL\n", i + i); ++ success = false; ++ } ++ } ++ ++ if (success) ++ pr_info("blake2s self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/chacha20poly1305.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++/* ChaCha20-Poly1305 AEAD test vectors from RFC7539 2.8.2 */ ++struct chacha20poly1305_testvec { ++ u8 *key, *nonce, *assoc, *input, *result; ++ size_t alen, ilen; ++}; ++static const struct chacha20poly1305_testvec chacha20poly1305_enc_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x01\x02\x03\x04\x05\x06\x07\x08", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d", ++ .ilen = 265, ++ .result = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38" ++} }; ++static const struct chacha20poly1305_testvec chacha20poly1305_dec_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x01\x02\x03\x04\x05\x06\x07\x08", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38", ++ .ilen = 281, ++ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d" ++} }; ++ ++static const struct chacha20poly1305_testvec xchacha20poly1305_enc_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d", ++ .ilen = 265, ++ .result = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c" ++} }; ++static const struct chacha20poly1305_testvec xchacha20poly1305_dec_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c", ++ .ilen = 281, ++ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d" ++} }; ++ ++bool chacha20poly1305_selftest(void) ++{ ++ size_t i; ++ u8 computed_result[512]; ++ bool success = true; ++ ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = chacha20poly1305_encrypt(computed_result, chacha20poly1305_enc_vectors[i].input, chacha20poly1305_enc_vectors[i].ilen, chacha20poly1305_enc_vectors[i].assoc, chacha20poly1305_enc_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_enc_vectors[i].nonce), chacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_result, chacha20poly1305_enc_vectors[i].result, chacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) { ++ pr_info("chacha20poly1305 encryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = chacha20poly1305_decrypt(computed_result, chacha20poly1305_dec_vectors[i].input, chacha20poly1305_dec_vectors[i].ilen, chacha20poly1305_dec_vectors[i].assoc, chacha20poly1305_dec_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_dec_vectors[i].nonce), chacha20poly1305_dec_vectors[i].key); ++ if (!success || memcmp(computed_result, chacha20poly1305_dec_vectors[i].result, chacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) { ++ pr_info("chacha20poly1305 decryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = xchacha20poly1305_encrypt(computed_result, xchacha20poly1305_enc_vectors[i].input, xchacha20poly1305_enc_vectors[i].ilen, xchacha20poly1305_enc_vectors[i].assoc, xchacha20poly1305_enc_vectors[i].alen, xchacha20poly1305_enc_vectors[i].nonce, xchacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_result, xchacha20poly1305_enc_vectors[i].result, xchacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) { ++ pr_info("xchacha20poly1305 encryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = xchacha20poly1305_decrypt(computed_result, xchacha20poly1305_dec_vectors[i].input, xchacha20poly1305_dec_vectors[i].ilen, xchacha20poly1305_dec_vectors[i].assoc, xchacha20poly1305_dec_vectors[i].alen, xchacha20poly1305_dec_vectors[i].nonce, xchacha20poly1305_dec_vectors[i].key); ++ if (!success || memcmp(computed_result, xchacha20poly1305_dec_vectors[i].result, xchacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) { ++ pr_info("xchacha20poly1305 decryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ if (success) ++ pr_info("chacha20poly1305 self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/counter.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++bool packet_counter_selftest(void) ++{ ++ bool success = true; ++ unsigned int test_num = 0, i; ++ union noise_counter counter; ++ ++#define T_INIT do { memset(&counter, 0, sizeof(union noise_counter)); spin_lock_init(&counter.receive.lock); } while (0) ++#define T_LIM (COUNTER_WINDOW_SIZE + 1) ++#define T(n, v) do { ++test_num; if (counter_validate(&counter, n) != v) { pr_info("nonce counter self-test %u: FAIL\n", test_num); success = false; } } while (0) ++ T_INIT; ++ /* 1 */ T(0, true); ++ /* 2 */ T(1, true); ++ /* 3 */ T(1, false); ++ /* 4 */ T(9, true); ++ /* 5 */ T(8, true); ++ /* 6 */ T(7, true); ++ /* 7 */ T(7, false); ++ /* 8 */ T(T_LIM, true); ++ /* 9 */ T(T_LIM - 1, true); ++ /* 10 */ T(T_LIM - 1, false); ++ /* 11 */ T(T_LIM - 2, true); ++ /* 12 */ T(2, true); ++ /* 13 */ T(2, false); ++ /* 14 */ T(T_LIM + 16, true); ++ /* 15 */ T(3, false); ++ /* 16 */ T(T_LIM + 16, false); ++ /* 17 */ T(T_LIM * 4, true); ++ /* 18 */ T(T_LIM * 4 - (T_LIM - 1), true); ++ /* 19 */ T(10, false); ++ /* 20 */ T(T_LIM * 4 - T_LIM, false); ++ /* 21 */ T(T_LIM * 4 - (T_LIM + 1), false); ++ /* 22 */ T(T_LIM * 4 - (T_LIM - 2), true); ++ /* 23 */ T(T_LIM * 4 + 1 - T_LIM, false); ++ /* 24 */ T(0, false); ++ /* 25 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 26 */ T(REJECT_AFTER_MESSAGES - 1, true); ++ /* 27 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 28 */ T(REJECT_AFTER_MESSAGES - 1, false); ++ /* 29 */ T(REJECT_AFTER_MESSAGES - 2, true); ++ /* 30 */ T(REJECT_AFTER_MESSAGES + 1, false); ++ /* 31 */ T(REJECT_AFTER_MESSAGES + 2, false); ++ /* 32 */ T(REJECT_AFTER_MESSAGES - 2, false); ++ /* 33 */ T(REJECT_AFTER_MESSAGES - 3, true); ++ /* 34 */ T(0, false); ++ ++ T_INIT; ++ for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i) ++ T(i, true); ++ T(0, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i) ++ T(i, true); ++ T(1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0 ;) ++ T(i, true); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1 ;) ++ T(i, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;) ++ T(i, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;) ++ T(i, true); ++ T(0, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++#undef T ++#undef T_LIM ++#undef T_INIT ++ ++ if (success) ++ pr_info("nonce counter self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/curve25519.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,66 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++struct curve25519_test_vector { ++ u8 private[CURVE25519_POINT_SIZE]; ++ u8 public[CURVE25519_POINT_SIZE]; ++ u8 result[CURVE25519_POINT_SIZE]; ++}; ++static const struct curve25519_test_vector curve25519_test_vectors[] = { ++ { ++ .private = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a }, ++ .public = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 } ++ }, ++ { ++ .private = { 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb }, ++ .public = { 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 } ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64, 0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d, 0xb, 0x95, 0x48, 0xdc, 0xc, 0xd8, 0x19, 0x98, 0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f } ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f, 0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d, 0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x8, 0xed, 0xe3, 0xb, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 } ++ }, ++ { ++ .private = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 }, ++ .public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 } ++ }, ++ { ++ .private = { 1, 2, 3, 4 }, ++ .public = { 0 }, ++ .result = { 0 } ++ }, ++ { ++ .private = { 2, 4, 6, 8 }, ++ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8 }, ++ .result = { 0 } ++ } ++}; ++bool curve25519_selftest(void) ++{ ++ bool success = true; ++ size_t i = 0; ++ u8 out[CURVE25519_POINT_SIZE]; ++ ++ for (i = 0; i < ARRAY_SIZE(curve25519_test_vectors); ++i) { ++ memset(out, 0, CURVE25519_POINT_SIZE); ++ curve25519(out, curve25519_test_vectors[i].private, curve25519_test_vectors[i].public); ++ if (memcmp(out, curve25519_test_vectors[i].result, CURVE25519_POINT_SIZE)) { ++ pr_info("curve25519 self-test %zu: FAIL\n", i + 1); ++ success = false; ++ break; ++ } ++ } ++ ++ if (success) ++ pr_info("curve25519 self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/routing-table.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,133 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++static inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d) ++{ ++ static struct in_addr ip; ++ u8 *split = (u8 *)&ip; ++ split[0] = a; ++ split[1] = b; ++ split[2] = c; ++ split[3] = d; ++ return &ip; ++} ++static inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d) ++{ ++ static struct in6_addr ip; ++ __be32 *split = (__be32 *)&ip; ++ split[0] = cpu_to_be32(a); ++ split[1] = cpu_to_be32(b); ++ split[2] = cpu_to_be32(c); ++ split[3] = cpu_to_be32(d); ++ return &ip; ++} ++ ++bool routing_table_selftest(void) ++{ ++ struct routing_table t; ++ struct wireguard_peer *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL; ++ size_t i = 0; ++ bool success = false; ++ struct in6_addr ip; ++ __be64 part; ++ ++ routing_table_init(&t); ++#define init_peer(name) do { name = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL); if (!name) goto free; kref_init(&name->refcount); } while (0) ++ init_peer(a); ++ init_peer(b); ++ init_peer(c); ++ init_peer(d); ++ init_peer(e); ++ init_peer(f); ++ init_peer(g); ++ init_peer(h); ++#undef init_peer ++ ++#define insert(version, mem, ipa, ipb, ipc, ipd, cidr) routing_table_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), cidr, mem) ++ insert(4, a, 192, 168, 4, 0, 24); ++ insert(4, b, 192, 168, 4, 4, 32); ++ insert(4, c, 192, 168, 0, 0, 16); ++ insert(4, d, 192, 95, 5, 64, 27); ++ insert(4, c, 192, 95, 5, 65, 27); /* replaces previous entry, and maskself is required */ ++ insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128); ++ insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64); ++ insert(4, e, 0, 0, 0, 0, 0); ++ insert(6, e, 0, 0, 0, 0, 0); ++ insert(6, f, 0, 0, 0, 0, 0); /* replaces previous entry */ ++ insert(6, g, 0x24046800, 0, 0, 0, 32); ++ insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64); /* maskself is required */ ++ insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128); ++ insert(4, g, 64, 15, 112, 0, 20); ++ insert(4, h, 64, 15, 123, 211, 25); /* maskself is required */ ++ insert(4, a, 10, 0, 0, 0, 25); ++ insert(4, b, 10, 0, 0, 128, 25); ++ insert(4, a, 10, 1, 0, 0, 30); ++ insert(4, b, 10, 1, 0, 4, 30); ++ insert(4, c, 10, 1, 0, 8, 29); ++ insert(4, d, 10, 1, 0, 16, 29); ++#undef insert ++ ++ success = true; ++#define test(version, mem, ipa, ipb, ipc, ipd) do { \ ++ bool _s = routing_table_lookup_v##version(&t, ip##version(ipa, ipb, ipc, ipd)) == mem; \ ++ ++i; \ ++ if (!_s) { \ ++ pr_info("routing table self-test %zu: FAIL\n", i); \ ++ success = false; \ ++ } \ ++} while (0) ++ test(4, a, 192, 168, 4, 20); ++ test(4, a, 192, 168, 4, 0); ++ test(4, b, 192, 168, 4, 4); ++ test(4, c, 192, 168, 200, 182); ++ test(4, c, 192, 95, 5, 68); ++ test(4, e, 192, 95, 5, 96); ++ test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543); ++ test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee); ++ test(6, f, 0x26075300, 0x60006b01, 0, 0); ++ test(6, g, 0x24046800, 0x40040806, 0, 0x1006); ++ test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0, 0); ++ test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010); ++ test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef); ++ test(4, g, 64, 15, 116, 26); ++ test(4, g, 64, 15, 127, 3); ++ test(4, g, 64, 15, 123, 1); ++ test(4, h, 64, 15, 123, 128); ++ test(4, h, 64, 15, 123, 129); ++ test(4, a, 10, 0, 0, 52); ++ test(4, b, 10, 0, 0, 220); ++ test(4, a, 10, 1, 0, 2); ++ test(4, b, 10, 1, 0, 6); ++ test(4, c, 10, 1, 0, 10); ++ test(4, d, 10, 1, 0, 20); ++#undef test ++ ++ /* These will hit the BUG_ON(len >= 128) in free_node if something goes wrong. */ ++ for (i = 0; i < 128; ++i) { ++ part = cpu_to_be64(~(1LLU << (i % 64))); ++ memset(&ip, 0xff, 16); ++ memcpy((u8 *)&ip + (i < 64) * 8, &part, 8); ++ routing_table_insert_v6(&t, &ip, 128, a); ++ } ++ ++ if (success) ++ pr_info("routing table self-tests: pass\n"); ++ ++free: ++ routing_table_free(&t); ++ kfree(a); ++ kfree(b); ++ kfree(c); ++ kfree(d); ++ kfree(e); ++ kfree(f); ++ kfree(g); ++ kfree(h); ++ ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/siphash.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Test cases for siphash.c ++ * ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4. ++ */ ++ ++#ifdef DEBUG ++ ++#include ++#include ++#include ++#include ++ ++/* Test vectors taken from official reference source available at: ++ * https://131002.net/siphash/siphash24.c ++ */ ++static const u64 test_vectors[64] = { ++ 0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL, ++ 0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL, ++ 0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL, ++ 0x9e0082df0ba9e4b0ULL, 0x7a5dbbc594ddb9f3ULL, 0xf4b32f46226bada7ULL, ++ 0x751e8fbc860ee5fbULL, 0x14ea5627c0843d90ULL, 0xf723ca908e7af2eeULL, ++ 0xa129ca6149be45e5ULL, 0x3f2acc7f57c29bdbULL, 0x699ae9f52cbe4794ULL, ++ 0x4bc1b3f0968dd39cULL, 0xbb6dc91da77961bdULL, 0xbed65cf21aa2ee98ULL, ++ 0xd0f2cbb02e3b67c7ULL, 0x93536795e3a33e88ULL, 0xa80c038ccd5ccec8ULL, ++ 0xb8ad50c6f649af94ULL, 0xbce192de8a85b8eaULL, 0x17d835b85bbb15f3ULL, ++ 0x2f2e6163076bcfadULL, 0xde4daaaca71dc9a5ULL, 0xa6a2506687956571ULL, ++ 0xad87a3535c49ef28ULL, 0x32d892fad841c342ULL, 0x7127512f72f27cceULL, ++ 0xa7f32346f95978e3ULL, 0x12e0b01abb051238ULL, 0x15e034d40fa197aeULL, ++ 0x314dffbe0815a3b4ULL, 0x027990f029623981ULL, 0xcadcd4e59ef40c4dULL, ++ 0x9abfd8766a33735cULL, 0x0e3ea96b5304a7d0ULL, 0xad0c42d6fc585992ULL, ++ 0x187306c89bc215a9ULL, 0xd4a60abcf3792b95ULL, 0xf935451de4f21df2ULL, ++ 0xa9538f0419755787ULL, 0xdb9acddff56ca510ULL, 0xd06c98cd5c0975ebULL, ++ 0xe612a3cb9ecba951ULL, 0xc766e62cfcadaf96ULL, 0xee64435a9752fe72ULL, ++ 0xa192d576b245165aULL, 0x0a8787bf8ecb74b2ULL, 0x81b3e73d20b49b6fULL, ++ 0x7fa8220ba3b2eceaULL, 0x245731c13ca42499ULL, 0xb78dbfaf3a8d83bdULL, ++ 0xea1ad565322a1a0bULL, 0x60e61c23a3795013ULL, 0x6606d7e446282b93ULL, ++ 0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL, ++ 0x958a324ceb064572ULL ++}; ++static const siphash_key_t test_key = ++ { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL }; ++ ++bool siphash_selftest(void) ++{ ++ u8 in[64] __aligned(SIPHASH_ALIGNMENT); ++ u8 in_unaligned[65]; ++ u8 i; ++ bool ret = true; ++ ++ for (i = 0; i < 64; ++i) { ++ in[i] = i; ++ in_unaligned[i + 1] = i; ++ if (siphash(in, i, test_key) != test_vectors[i]) { ++ pr_info("siphash self-test aligned %u: FAIL\n", i + 1); ++ ret = false; ++ } ++ if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) { ++ pr_info("siphash self-test unaligned %u: FAIL\n", i + 1); ++ ret = false; ++ } ++ } ++ if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) { ++ pr_info("siphash self-test 1u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) { ++ pr_info("siphash self-test 2u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, ++ 0x1716151413121110ULL, test_key) != test_vectors[24]) { ++ pr_info("siphash self-test 3u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, ++ 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) { ++ pr_info("siphash self-test 4u64: FAIL\n"); ++ ret = false; ++ } ++ if (ret) ++ pr_info("siphash self-tests: pass\n"); ++ return ret; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/blake2s.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,278 @@ ++/* Original author: Samuel Neves ++ * ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "blake2s.h" ++ ++#include ++#include ++#include ++ ++typedef struct { ++ u8 digest_length; ++ u8 key_length; ++ u8 fanout; ++ u8 depth; ++ u32 leaf_length; ++ u8 node_offset[6]; ++ u8 node_depth; ++ u8 inner_length; ++ u8 salt[8]; ++ u8 personal[8]; ++} __packed blake2s_param; ++ ++static const u32 blake2s_iv[8] = { ++ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, ++ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL ++}; ++ ++static const u8 blake2s_sigma[10][16] = { ++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, ++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, ++ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, ++ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, ++ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, ++ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, ++ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, ++ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, ++ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, ++ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, ++}; ++ ++static inline u32 le32_to_cpuvp(const void *p) ++{ ++ return le32_to_cpup(p); ++} ++ ++static inline void blake2s_set_lastblock(struct blake2s_state *state) ++{ ++ if (state->last_node) ++ state->f[1] = -1; ++ state->f[0] = -1; ++} ++ ++static inline void blake2s_increment_counter(struct blake2s_state *state, const u32 inc) ++{ ++ state->t[0] += inc; ++ state->t[1] += (state->t[0] < inc); ++} ++ ++static inline void blake2s_init_param(struct blake2s_state *state, const blake2s_param *param) ++{ ++ const u32 *p; ++ int i; ++ memset(state, 0, sizeof(struct blake2s_state)); ++ for (i = 0; i < 8; ++i) ++ state->h[i] = blake2s_iv[i]; ++ p = (const u32 *)param; ++ /* IV XOR ParamBlock */ ++ for (i = 0; i < 8; ++i) ++ state->h[i] ^= le32_to_cpuvp(&p[i]); ++} ++ ++void blake2s_init(struct blake2s_state *state, const u8 outlen) ++{ ++ blake2s_param param = { ++ .digest_length = outlen, ++ .fanout = 1, ++ .depth = 1 ++ }; ++ ++#ifdef DEBUG ++ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES); ++#endif ++ blake2s_init_param(state, ¶m); ++} ++ ++void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen) ++{ ++ blake2s_param param = { ++ .digest_length = outlen, ++ .key_length = keylen, ++ .fanout = 1, ++ .depth = 1 ++ }; ++ u8 block[BLAKE2S_BLOCKBYTES] = { 0 }; ++ ++#ifdef DEBUG ++ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES || !key || !keylen || keylen > BLAKE2S_KEYBYTES); ++#endif ++ blake2s_init_param(state, ¶m); ++ memcpy(block, key, keylen); ++ blake2s_update(state, block, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(block, BLAKE2S_BLOCKBYTES); ++} ++ ++static inline void blake2s_compress(struct blake2s_state *state, const u8 block[BLAKE2S_BLOCKBYTES]) ++{ ++ u32 m[16]; ++ u32 v[16]; ++ int i; ++ ++ for (i = 0; i < 16; ++i) ++ m[i] = le32_to_cpuvp(block + i * sizeof(m[i])); ++ ++ for (i = 0; i < 8; ++i) ++ v[i] = state->h[i]; ++ ++ v[8] = blake2s_iv[0]; ++ v[9] = blake2s_iv[1]; ++ v[10] = blake2s_iv[2]; ++ v[11] = blake2s_iv[3]; ++ v[12] = state->t[0] ^ blake2s_iv[4]; ++ v[13] = state->t[1] ^ blake2s_iv[5]; ++ v[14] = state->f[0] ^ blake2s_iv[6]; ++ v[15] = state->f[1] ^ blake2s_iv[7]; ++#define G(r,i,a,b,c,d) \ ++ do { \ ++ a += b + m[blake2s_sigma[r][2 * i + 0]]; \ ++ d = ror32(d ^ a, 16); \ ++ c += d; \ ++ b = ror32(b ^ c, 12); \ ++ a += b + m[blake2s_sigma[r][2 * i + 1]]; \ ++ d = ror32(d ^ a, 8); \ ++ c += d; \ ++ b = ror32(b ^ c, 7); \ ++ } while(0) ++#define ROUND(r) \ ++ do { \ ++ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ ++ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ ++ G(r,2,v[ 2],v[ 6],v[10],v[14]); \ ++ G(r,3,v[ 3],v[ 7],v[11],v[15]); \ ++ G(r,4,v[ 0],v[ 5],v[10],v[15]); \ ++ G(r,5,v[ 1],v[ 6],v[11],v[12]); \ ++ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ ++ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ ++} while(0) ++ ROUND(0); ++ ROUND(1); ++ ROUND(2); ++ ROUND(3); ++ ROUND(4); ++ ROUND(5); ++ ROUND(6); ++ ROUND(7); ++ ROUND(8); ++ ROUND(9); ++ ++ for (i = 0; i < 8; ++i) ++ state->h[i] = state->h[i] ^ v[i] ^ v[i + 8]; ++#undef G ++#undef ROUND ++} ++ ++void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen) ++{ ++ size_t left, fill; ++ while (inlen > 0) { ++ left = state->buflen; ++ fill = 2 * BLAKE2S_BLOCKBYTES - left; ++ ++ if (inlen > fill) { ++ memcpy(state->buf + left, in, fill); // Fill buffer ++ state->buflen += fill; ++ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES); ++ blake2s_compress(state, state->buf); // Compress ++ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES);// Shift buffer left ++ state->buflen -= BLAKE2S_BLOCKBYTES; ++ in += fill; ++ inlen -= fill; ++ } else { // inlen <= fill ++ memcpy(state->buf + left, in, inlen); ++ state->buflen += inlen; // Be lazy, do not compress ++ in += inlen; ++ inlen -= inlen; ++ } ++ } ++} ++ ++void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen) ++{ ++ u8 buffer[BLAKE2S_OUTBYTES] = { 0 }; ++ int i; ++ ++#ifdef DEBUG ++ BUG_ON(!out || !outlen || outlen > BLAKE2S_OUTBYTES); ++#endif ++ ++ if (state->buflen > BLAKE2S_BLOCKBYTES) { ++ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES); ++ blake2s_compress(state, state->buf); ++ state->buflen -= BLAKE2S_BLOCKBYTES; ++ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, state->buflen); ++ } ++ ++ blake2s_increment_counter(state, (u32) state->buflen); ++ blake2s_set_lastblock(state); ++ memset(state->buf + state->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - state->buflen); /* Padding */ ++ blake2s_compress(state, state->buf); ++ ++ for (i = 0; i < 8; ++i) /* output full hash to temp buffer */ ++ *(__le32 *)(buffer + sizeof(state->h[i]) * i) = cpu_to_le32(state->h[i]); ++ ++ memcpy(out, buffer, outlen); ++ ++ /* Burn state from stack */ ++ memzero_explicit(buffer, BLAKE2S_OUTBYTES); ++ memzero_explicit(state, sizeof(struct blake2s_state)); ++} ++ ++void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, u64 inlen, const u8 keylen) ++{ ++ struct blake2s_state state; ++ ++#ifdef DEBUG ++ BUG_ON((!in && inlen > 0) || !out || !outlen || outlen > BLAKE2S_OUTBYTES || keylen > BLAKE2S_KEYBYTES); ++#endif ++ ++ if (keylen > 0 && key) ++ blake2s_init_key(&state, outlen, key, keylen); ++ else ++ blake2s_init(&state, outlen); ++ ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, out, outlen); ++} ++ ++void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen) ++{ ++ struct blake2s_state state; ++ u8 o_key[BLAKE2S_BLOCKBYTES] = { 0 }; ++ u8 i_key[BLAKE2S_BLOCKBYTES] = { 0 }; ++ u8 i_hash[BLAKE2S_OUTBYTES]; ++ int i; ++ ++ if (keylen > BLAKE2S_BLOCKBYTES) { ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, key, keylen); ++ blake2s_final(&state, o_key, BLAKE2S_OUTBYTES); ++ memcpy(i_key, o_key, BLAKE2S_OUTBYTES); ++ } else { ++ memcpy(o_key, key, keylen); ++ memcpy(i_key, key, keylen); ++ } ++ ++ for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) { ++ o_key[i] ^= 0x5c; ++ i_key[i] ^= 0x36; ++ } ++ ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, i_key, BLAKE2S_BLOCKBYTES); ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES); ++ ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, o_key, BLAKE2S_BLOCKBYTES); ++ blake2s_update(&state, i_hash, BLAKE2S_OUTBYTES); ++ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES); ++ ++ memcpy(out, i_hash, outlen); ++ memzero_explicit(o_key, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(i_key, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(i_hash, BLAKE2S_OUTBYTES); ++} ++ ++#include "../selftest/blake2s.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20poly1305.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,811 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * Copyright 2015 Martin Willi. ++ */ ++ ++#include "chacha20poly1305.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_X86_64 ++#include ++#include ++#ifdef CONFIG_AS_SSSE3 ++asmlinkage void chacha20_asm_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src); ++asmlinkage void chacha20_asm_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src); ++#endif ++#ifdef CONFIG_AS_AVX2 ++asmlinkage void chacha20_asm_8block_xor_avx2(u32 *state, u8 *dst, const u8 *src); ++#endif ++asmlinkage void poly1305_asm_block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks); ++asmlinkage void poly1305_asm_2block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u); ++#ifdef CONFIG_AS_AVX2 ++asmlinkage void poly1305_asm_4block_avx2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u); ++#endif ++static bool chacha20poly1305_use_avx2 __read_mostly = false; ++static bool chacha20poly1305_use_ssse3 __read_mostly = false; ++static bool chacha20poly1305_use_sse2 __read_mostly = false; ++void chacha20poly1305_init(void) ++{ ++ chacha20poly1305_use_sse2 = boot_cpu_has(X86_FEATURE_XMM2); ++ chacha20poly1305_use_ssse3 = boot_cpu_has(X86_FEATURE_SSSE3); ++ chacha20poly1305_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) && boot_cpu_has(X86_FEATURE_AVX2); ++} ++#else ++void chacha20poly1305_init(void) { } ++#endif ++ ++#define CHACHA20_IV_SIZE 16 ++#define CHACHA20_KEY_SIZE 32 ++#define CHACHA20_BLOCK_SIZE 64 ++#define POLY1305_BLOCK_SIZE 16 ++#define POLY1305_KEY_SIZE 32 ++#define POLY1305_MAC_SIZE 16 ++ ++static inline u32 le32_to_cpuvp(const void *p) ++{ ++ return le32_to_cpup(p); ++} ++ ++static inline u64 le64_to_cpuvp(const void *p) ++{ ++ return le64_to_cpup(p); ++} ++ ++static inline u32 rotl32(u32 v, u8 n) ++{ ++ return (v << n) | (v >> (sizeof(v) * 8 - n)); ++} ++ ++static inline u64 mlt(u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++static inline u32 sr(u64 v, u_char n) ++{ ++ return v >> n; ++} ++ ++static inline u32 and(u32 v, u32 mask) ++{ ++ return v & mask; ++} ++ ++struct chacha20_ctx { ++ u32 state[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++} __aligned(32); ++ ++static void chacha20_generic_block(struct chacha20_ctx *ctx, void *stream) ++{ ++ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++ __le32 *out = stream; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(x); i++) ++ x[i] = ctx->state[i]; ++ ++ for (i = 0; i < 20; i += 2) { ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12); ++ ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(x); i++) ++ out[i] = cpu_to_le32(x[i] + ctx->state[i]); ++ ++ ctx->state[12]++; ++} ++ ++static const char constant[16] = "expand 32-byte k"; ++ ++static void hchacha20(u8 derived_key[CHACHA20POLY1305_KEYLEN], const u8 nonce[16], const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++ __le32 *out = (__force __le32 *)derived_key; ++ int i; ++ ++ x[0] = le32_to_cpuvp(constant + 0); ++ x[1] = le32_to_cpuvp(constant + 4); ++ x[2] = le32_to_cpuvp(constant + 8); ++ x[3] = le32_to_cpuvp(constant + 12); ++ x[4] = le32_to_cpuvp(key + 0); ++ x[5] = le32_to_cpuvp(key + 4); ++ x[6] = le32_to_cpuvp(key + 8); ++ x[7] = le32_to_cpuvp(key + 12); ++ x[8] = le32_to_cpuvp(key + 16); ++ x[9] = le32_to_cpuvp(key + 20); ++ x[10] = le32_to_cpuvp(key + 24); ++ x[11] = le32_to_cpuvp(key + 28); ++ x[12] = le32_to_cpuvp(nonce + 0); ++ x[13] = le32_to_cpuvp(nonce + 4); ++ x[14] = le32_to_cpuvp(nonce + 8); ++ x[15] = le32_to_cpuvp(nonce + 12); ++ ++ for (i = 0; i < 20; i += 2) { ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12); ++ ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7); ++ } ++ ++ out[0] = cpu_to_le32(x[0]); ++ out[1] = cpu_to_le32(x[1]); ++ out[2] = cpu_to_le32(x[2]); ++ out[3] = cpu_to_le32(x[3]); ++ out[4] = cpu_to_le32(x[12]); ++ out[5] = cpu_to_le32(x[13]); ++ out[6] = cpu_to_le32(x[14]); ++ out[7] = cpu_to_le32(x[15]); ++} ++ ++static void chacha20_keysetup(struct chacha20_ctx *ctx, const u8 key[CHACHA20_KEY_SIZE], const u8 nonce[sizeof(u64)]) ++{ ++ ctx->state[0] = le32_to_cpuvp(constant + 0); ++ ctx->state[1] = le32_to_cpuvp(constant + 4); ++ ctx->state[2] = le32_to_cpuvp(constant + 8); ++ ctx->state[3] = le32_to_cpuvp(constant + 12); ++ ctx->state[4] = le32_to_cpuvp(key + 0); ++ ctx->state[5] = le32_to_cpuvp(key + 4); ++ ctx->state[6] = le32_to_cpuvp(key + 8); ++ ctx->state[7] = le32_to_cpuvp(key + 12); ++ ctx->state[8] = le32_to_cpuvp(key + 16); ++ ctx->state[9] = le32_to_cpuvp(key + 20); ++ ctx->state[10] = le32_to_cpuvp(key + 24); ++ ctx->state[11] = le32_to_cpuvp(key + 28); ++ ctx->state[12] = 0; ++ ctx->state[13] = 0; ++ ctx->state[14] = le32_to_cpuvp(nonce + 0); ++ ctx->state[15] = le32_to_cpuvp(nonce + 4); ++} ++ ++static void chacha20_crypt(struct chacha20_ctx *ctx, u8 *dst, const u8 *src, unsigned int bytes, bool have_simd) ++{ ++ u8 buf[CHACHA20_BLOCK_SIZE]; ++ ++ if (!have_simd ++#ifdef CONFIG_X86_64 ++ || !chacha20poly1305_use_ssse3 ++#endif ++ ) ++ goto no_simd; ++ ++#ifdef CONFIG_X86_64 ++#ifdef CONFIG_AS_AVX2 ++ if (chacha20poly1305_use_avx2) { ++ while (bytes >= CHACHA20_BLOCK_SIZE * 8) { ++ chacha20_asm_8block_xor_avx2(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE * 8; ++ src += CHACHA20_BLOCK_SIZE * 8; ++ dst += CHACHA20_BLOCK_SIZE * 8; ++ ctx->state[12] += 8; ++ } ++ } ++#endif ++#ifdef CONFIG_AS_SSSE3 ++ while (bytes >= CHACHA20_BLOCK_SIZE * 4) { ++ chacha20_asm_4block_xor_ssse3(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE * 4; ++ src += CHACHA20_BLOCK_SIZE * 4; ++ dst += CHACHA20_BLOCK_SIZE * 4; ++ ctx->state[12] += 4; ++ } ++ while (bytes >= CHACHA20_BLOCK_SIZE) { ++ chacha20_asm_block_xor_ssse3(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE; ++ src += CHACHA20_BLOCK_SIZE; ++ dst += CHACHA20_BLOCK_SIZE; ++ ctx->state[12]++; ++ } ++ if (bytes) { ++ memcpy(buf, src, bytes); ++ chacha20_asm_block_xor_ssse3(ctx->state, buf, buf); ++ memcpy(dst, buf, bytes); ++ } ++ return; ++#endif ++#endif ++ ++no_simd: ++ if (dst != src) ++ memcpy(dst, src, bytes); ++ ++ while (bytes >= CHACHA20_BLOCK_SIZE) { ++ chacha20_generic_block(ctx, buf); ++ crypto_xor(dst, buf, CHACHA20_BLOCK_SIZE); ++ bytes -= CHACHA20_BLOCK_SIZE; ++ dst += CHACHA20_BLOCK_SIZE; ++ } ++ if (bytes) { ++ chacha20_generic_block(ctx, buf); ++ crypto_xor(dst, buf, bytes); ++ } ++} ++ ++struct poly1305_ctx { ++ /* key */ ++ u32 r[5]; ++ /* finalize key */ ++ u32 s[4]; ++ /* accumulator */ ++ u32 h[5]; ++ /* partial buffer */ ++ u8 buf[POLY1305_BLOCK_SIZE]; ++ /* bytes used in partial buffer */ ++ unsigned int buflen; ++ /* derived key u set? */ ++ bool uset; ++ /* derived keys r^3, r^4 set? */ ++ bool wset; ++ /* derived Poly1305 key r^2 */ ++ u32 u[5]; ++ /* derived Poly1305 key r^3 */ ++ u32 r3[5]; ++ /* derived Poly1305 key r^4 */ ++ u32 r4[5]; ++}; ++ ++static void poly1305_init(struct poly1305_ctx *ctx, const u8 key[POLY1305_KEY_SIZE]) ++{ ++ memset(ctx, 0, sizeof(struct poly1305_ctx)); ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ ctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff; ++ ctx->r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03; ++ ctx->r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff; ++ ctx->r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff; ++ ctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff; ++ ctx->s[0] = le32_to_cpuvp(key + 16); ++ ctx->s[1] = le32_to_cpuvp(key + 20); ++ ctx->s[2] = le32_to_cpuvp(key + 24); ++ ctx->s[3] = le32_to_cpuvp(key + 28); ++} ++ ++static unsigned int poly1305_generic_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, u32 hibit) ++{ ++ u32 r0, r1, r2, r3, r4; ++ u32 s1, s2, s3, s4; ++ u32 h0, h1, h2, h3, h4; ++ u64 d0, d1, d2, d3, d4; ++ ++ r0 = ctx->r[0]; ++ r1 = ctx->r[1]; ++ r2 = ctx->r[2]; ++ r3 = ctx->r[3]; ++ r4 = ctx->r[4]; ++ ++ s1 = r1 * 5; ++ s2 = r2 * 5; ++ s3 = r3 * 5; ++ s4 = r4 * 5; ++ ++ h0 = ctx->h[0]; ++ h1 = ctx->h[1]; ++ h2 = ctx->h[2]; ++ h3 = ctx->h[3]; ++ h4 = ctx->h[4]; ++ ++ while (likely(srclen >= POLY1305_BLOCK_SIZE)) { ++ /* h += m[i] */ ++ h0 += (le32_to_cpuvp(src + 0) >> 0) & 0x3ffffff; ++ h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; ++ h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; ++ h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; ++ h4 += (le32_to_cpuvp(src + 12) >> 8) | hibit; ++ ++ /* h *= r */ ++ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + mlt(h3, s2) + mlt(h4, s1); ++ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + mlt(h3, s3) + mlt(h4, s2); ++ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + mlt(h3, s4) + mlt(h4, s3); ++ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + mlt(h3, r0) + mlt(h4, s4); ++ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + mlt(h3, r1) + mlt(h4, r0); ++ ++ /* (partial) h %= p */ ++ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); ++ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); ++ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); ++ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); ++ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); ++ h1 += h0 >> 26; h0 = h0 & 0x3ffffff; ++ ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ } ++ ++ ctx->h[0] = h0; ++ ctx->h[1] = h1; ++ ctx->h[2] = h2; ++ ctx->h[3] = h3; ++ ctx->h[4] = h4; ++ ++ return srclen; ++} ++ ++#ifdef CONFIG_X86_64 ++static void poly1305_simd_mult(u32 *a, const u32 *b) ++{ ++ u8 m[POLY1305_BLOCK_SIZE]; ++ ++ memset(m, 0, sizeof(m)); ++ /* The poly1305 block function adds a hi-bit to the accumulator which ++ * we don't need for key multiplication; compensate for it. */ ++ a[4] -= 1 << 24; ++ poly1305_asm_block_sse2(a, m, b, 1); ++} ++ ++static unsigned int poly1305_simd_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen) ++{ ++ unsigned int blocks; ++ ++#ifdef CONFIG_AS_AVX2 ++ if (chacha20poly1305_use_avx2 && srclen >= POLY1305_BLOCK_SIZE * 4) { ++ if (unlikely(!ctx->wset)) { ++ if (!ctx->uset) { ++ memcpy(ctx->u, ctx->r, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->u, ctx->r); ++ ctx->uset = true; ++ } ++ memcpy(ctx->r3, ctx->u, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->r3, ctx->r); ++ memcpy(ctx->r4, ctx->r3, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->r4, ctx->r); ++ ctx->wset = true; ++ } ++ blocks = srclen / (POLY1305_BLOCK_SIZE * 4); ++ poly1305_asm_4block_avx2(ctx->h, src, ctx->r, blocks, ctx->u); ++ src += POLY1305_BLOCK_SIZE * 4 * blocks; ++ srclen -= POLY1305_BLOCK_SIZE * 4 * blocks; ++ } ++#endif ++ if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) { ++ if (unlikely(!ctx->uset)) { ++ memcpy(ctx->u, ctx->r, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->u, ctx->r); ++ ctx->uset = true; ++ } ++ blocks = srclen / (POLY1305_BLOCK_SIZE * 2); ++ poly1305_asm_2block_sse2(ctx->h, src, ctx->r, blocks, ctx->u); ++ src += POLY1305_BLOCK_SIZE * 2 * blocks; ++ srclen -= POLY1305_BLOCK_SIZE * 2 * blocks; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_asm_block_sse2(ctx->h, src, ctx->r, 1); ++ srclen -= POLY1305_BLOCK_SIZE; ++ } ++ return srclen; ++} ++#endif ++ ++static void poly1305_update(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, bool have_simd) ++{ ++ unsigned int bytes; ++ ++ if (unlikely(ctx->buflen)) { ++ bytes = min(srclen, POLY1305_BLOCK_SIZE - ctx->buflen); ++ memcpy(ctx->buf + ctx->buflen, src, bytes); ++ src += bytes; ++ srclen -= bytes; ++ ctx->buflen += bytes; ++ ++ if (ctx->buflen == POLY1305_BLOCK_SIZE) { ++#ifdef CONFIG_X86_64 ++ ++ if (have_simd && chacha20poly1305_use_sse2) ++ poly1305_simd_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE); ++ else ++#endif ++ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 1 << 24); ++ ctx->buflen = 0; ++ } ++ } ++ ++ if (likely(srclen >= POLY1305_BLOCK_SIZE)) { ++#ifdef CONFIG_X86_64 ++ ++ if (have_simd && chacha20poly1305_use_sse2) ++ bytes = poly1305_simd_blocks(ctx, src, srclen); ++ else ++#endif ++ bytes = poly1305_generic_blocks(ctx, src, srclen, 1 << 24); ++ src += srclen - bytes; ++ srclen = bytes; ++ } ++ ++ if (unlikely(srclen)) { ++ ctx->buflen = srclen; ++ memcpy(ctx->buf, src, srclen); ++ } ++} ++ ++static void poly1305_finish(struct poly1305_ctx *ctx, u8 *dst) ++{ ++ __le32 *mac = (__le32 *)dst; ++ u32 h0, h1, h2, h3, h4; ++ u32 g0, g1, g2, g3, g4; ++ u32 mask; ++ u64 f = 0; ++ ++ if (unlikely(ctx->buflen)) { ++ ctx->buf[ctx->buflen++] = 1; ++ memset(ctx->buf + ctx->buflen, 0, POLY1305_BLOCK_SIZE - ctx->buflen); ++ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 0); ++ } ++ ++ /* fully carry h */ ++ h0 = ctx->h[0]; ++ h1 = ctx->h[1]; ++ h2 = ctx->h[2]; ++ h3 = ctx->h[3]; ++ h4 = ctx->h[4]; ++ ++ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; ++ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; ++ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; ++ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; ++ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; ++ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; ++ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; ++ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; ++ g0 &= mask; ++ g1 &= mask; ++ g2 &= mask; ++ g3 &= mask; ++ g4 &= mask; ++ mask = ~mask; ++ h0 = (h0 & mask) | g0; ++ h1 = (h1 & mask) | g1; ++ h2 = (h2 & mask) | g2; ++ h3 = (h3 & mask) | g3; ++ h4 = (h4 & mask) | g4; ++ ++ /* h = h % (2^128) */ ++ h0 = (h0 >> 0) | (h1 << 26); ++ h1 = (h1 >> 6) | (h2 << 20); ++ h2 = (h2 >> 12) | (h3 << 14); ++ h3 = (h3 >> 18) | (h4 << 8); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + h0 + ctx->s[0]; mac[0] = cpu_to_le32(f); ++ f = (f >> 32) + h1 + ctx->s[1]; mac[1] = cpu_to_le32(f); ++ f = (f >> 32) + h2 + ctx->s[2]; mac[2] = cpu_to_le32(f); ++ f = (f >> 32) + h3 + ctx->s[3]; mac[3] = cpu_to_le32(f); ++} ++ ++static const u8 pad0[16] = { 0 }; ++ ++static struct crypto_alg chacha20_alg = { ++ .cra_blocksize = 1, ++ .cra_alignmask = sizeof(u32) - 1 ++}; ++static struct crypto_blkcipher chacha20_cipher = { ++ .base = { ++ .__crt_alg = &chacha20_alg ++ } ++}; ++static struct blkcipher_desc chacha20_desc = { ++ .tfm = &chacha20_cipher ++}; ++ ++bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ chacha20_crypt(&chacha20_state, dst, src, src_len, have_simd); ++ ++ poly1305_update(&poly1305_state, dst, src_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, dst + src_len); ++ ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ ++ chacha20poly1305_deinit_simd(have_simd); ++ ++ return true; ++} ++ ++bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN], ++ bool have_simd) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ struct blkcipher_walk walk; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 mac[POLY1305_MAC_SIZE]; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ if (likely(src_len)) { ++ blkcipher_walk_init(&walk, dst, src, src_len); ++ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE); ++ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) { ++ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd); ++ poly1305_update(&poly1305_state, walk.dst.virt.addr, chunk_len, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE); ++ } ++ if (walk.nbytes) { ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd); ++ poly1305_update(&poly1305_state, walk.dst.virt.addr, walk.nbytes, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, 0); ++ } ++ } ++ ++ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, mac); ++ scatterwalk_map_and_copy(mac, dst, src_len, sizeof(mac), 1); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ memzero_explicit(mac, sizeof(mac)); ++ return true; ++} ++ ++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ int ret; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 mac[POLY1305_MAC_SIZE]; ++ size_t dst_len; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd; ++ ++ if (unlikely(src_len < POLY1305_MAC_SIZE)) ++ return false; ++ ++ have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ dst_len = src_len - POLY1305_MAC_SIZE; ++ poly1305_update(&poly1305_state, src, dst_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(dst_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, mac); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ ++ ret = crypto_memneq(mac, src + dst_len, POLY1305_MAC_SIZE); ++ memzero_explicit(mac, POLY1305_MAC_SIZE); ++ if (likely(!ret)) ++ chacha20_crypt(&chacha20_state, dst, src, dst_len, have_simd); ++ ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ ++ chacha20poly1305_deinit_simd(have_simd); ++ return !ret; ++} ++ ++bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ struct blkcipher_walk walk; ++ int ret; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 read_mac[POLY1305_MAC_SIZE], computed_mac[POLY1305_MAC_SIZE]; ++ size_t dst_len; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd; ++ ++ if (unlikely(src_len < POLY1305_MAC_SIZE)) ++ return false; ++ ++ have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ dst_len = src_len - POLY1305_MAC_SIZE; ++ if (likely(dst_len)) { ++ blkcipher_walk_init(&walk, dst, src, dst_len); ++ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE); ++ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) { ++ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE); ++ poly1305_update(&poly1305_state, walk.src.virt.addr, chunk_len, have_simd); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE); ++ } ++ if (walk.nbytes) { ++ poly1305_update(&poly1305_state, walk.src.virt.addr, walk.nbytes, have_simd); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, 0); ++ } ++ } ++ ++ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(dst_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, computed_mac); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ ++ scatterwalk_map_and_copy(read_mac, src, dst_len, POLY1305_MAC_SIZE, 0); ++ ret = crypto_memneq(read_mac, computed_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(read_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(computed_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ chacha20poly1305_deinit_simd(have_simd); ++ return !ret; ++} ++ ++ ++bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u8 derived_key[CHACHA20POLY1305_KEYLEN]; ++ bool ret; ++ hchacha20(derived_key, nonce, key); ++ ret = chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key); ++ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN); ++ return ret; ++} ++ ++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u8 derived_key[CHACHA20POLY1305_KEYLEN]; ++ bool ret; ++ hchacha20(derived_key, nonce, key); ++ ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key); ++ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN); ++ return ret; ++} ++ ++#include "../selftest/chacha20poly1305.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/curve25519.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,1240 @@ ++/* Original author: Adam Langley ++ * ++ * Copyright 2008 Google Inc. All Rights Reserved. ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "curve25519.h" ++ ++#include ++#include ++#include ++ ++static __always_inline void normalize_secret(u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ secret[0] &= 248; ++ secret[31] &= 127; ++ secret[31] |= 64; ++} ++ ++#ifdef __SIZEOF_INT128__ ++typedef u64 limb; ++typedef limb felem[5]; ++typedef __uint128_t uint128_t; ++ ++/* Sum two numbers: output += in */ ++static __always_inline void fsum(limb *output, const limb *in) ++{ ++ output[0] += in[0]; ++ output[1] += in[1]; ++ output[2] += in[2]; ++ output[3] += in[3]; ++ output[4] += in[4]; ++} ++ ++/* Find the difference of two numbers: output = in - output ++ * (note the order of the arguments!) ++ * ++ * Assumes that out[i] < 2**52 ++ * On return, out[i] < 2**55 ++ */ ++static __always_inline void fdifference_backwards(felem out, const felem in) ++{ ++ /* 152 is 19 << 3 */ ++ static const limb two54m152 = (((limb)1) << 54) - 152; ++ static const limb two54m8 = (((limb)1) << 54) - 8; ++ ++ out[0] = in[0] + two54m152 - out[0]; ++ out[1] = in[1] + two54m8 - out[1]; ++ out[2] = in[2] + two54m8 - out[2]; ++ out[3] = in[3] + two54m8 - out[3]; ++ out[4] = in[4] + two54m8 - out[4]; ++} ++ ++/* Multiply a number by a scalar: output = in * scalar */ ++static __always_inline void fscalar_product(felem output, const felem in, const limb scalar) ++{ ++ uint128_t a; ++ ++ a = ((uint128_t) in[0]) * scalar; ++ output[0] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51)); ++ output[1] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51)); ++ output[2] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51)); ++ output[3] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51)); ++ output[4] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ output[0] += (a >> 51) * 19; ++} ++ ++/* Multiply two numbers: output = in2 * in ++ * ++ * output must be distinct to both inputs. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * Assumes that in[i] < 2**55 and likewise for in2. ++ * On return, output[i] < 2**52 ++ */ ++static __always_inline void fmul(felem output, const felem in2, const felem in) ++{ ++ uint128_t t[5]; ++ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; ++ ++ r0 = in[0]; ++ r1 = in[1]; ++ r2 = in[2]; ++ r3 = in[3]; ++ r4 = in[4]; ++ ++ s0 = in2[0]; ++ s1 = in2[1]; ++ s2 = in2[2]; ++ s3 = in2[3]; ++ s4 = in2[4]; ++ ++ t[0] = ((uint128_t) r0) * s0; ++ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; ++ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; ++ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; ++ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; ++ ++ r4 *= 19; ++ r1 *= 19; ++ r2 *= 19; ++ r3 *= 19; ++ ++ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; ++ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; ++ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; ++ t[3] += ((uint128_t) r4) * s4; ++ ++ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51); ++ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51); ++ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51); ++ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51); ++ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51); ++ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL; ++ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL; ++ r2 += c; ++ ++ output[0] = r0; ++ output[1] = r1; ++ output[2] = r2; ++ output[3] = r3; ++ output[4] = r4; ++} ++ ++static __always_inline void fsquare_times(felem output, const felem in, limb count) ++{ ++ uint128_t t[5]; ++ limb r0,r1,r2,r3,r4,c; ++ limb d0,d1,d2,d4,d419; ++ ++ r0 = in[0]; ++ r1 = in[1]; ++ r2 = in[2]; ++ r3 = in[3]; ++ r4 = in[4]; ++ ++ do { ++ d0 = r0 * 2; ++ d1 = r1 * 2; ++ d2 = r2 * 2 * 19; ++ d419 = r4 * 19; ++ d4 = d419 * 2; ++ ++ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); ++ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); ++ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); ++ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); ++ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); ++ ++ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51); ++ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51); ++ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51); ++ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51); ++ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51); ++ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL; ++ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL; ++ r2 += c; ++ } while(--count); ++ ++ output[0] = r0; ++ output[1] = r1; ++ output[2] = r2; ++ output[3] = r3; ++ output[4] = r4; ++} ++ ++/* Load a little-endian 64-bit number */ ++static inline limb load_limb(const u8 *in) ++{ ++ return le64_to_cpu(*(u64 *)in); ++} ++ ++static inline void store_limb(u8 *out, limb in) ++{ ++ *(u64 *)out = cpu_to_le64(in); ++} ++ ++/* Take a little-endian, 32-byte number and expand it into polynomial form */ ++static inline void fexpand(limb *output, const u8 *in) ++{ ++ output[0] = load_limb(in) & 0x7ffffffffffffUL; ++ output[1] = (load_limb(in + 6) >> 3) & 0x7ffffffffffffUL; ++ output[2] = (load_limb(in + 12) >> 6) & 0x7ffffffffffffUL; ++ output[3] = (load_limb(in + 19) >> 1) & 0x7ffffffffffffUL; ++ output[4] = (load_limb(in + 24) >> 12) & 0x7ffffffffffffUL; ++} ++ ++/* Take a fully reduced polynomial form number and contract it into a ++ * little-endian, 32-byte array ++ */ ++static void fcontract(u8 *output, const felem input) ++{ ++ uint128_t t[5]; ++ ++ t[0] = input[0]; ++ t[1] = input[1]; ++ t[2] = input[2]; ++ t[3] = input[3]; ++ t[4] = input[4]; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ /* now t is between 0 and 2^255-1, properly carried. */ ++ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ ++ ++ t[0] += 19; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ /* now between 19 and 2^255-1 in both cases, and offset by 19. */ ++ ++ t[0] += 0x8000000000000UL - 19; ++ t[1] += 0x8000000000000UL - 1; ++ t[2] += 0x8000000000000UL - 1; ++ t[3] += 0x8000000000000UL - 1; ++ t[4] += 0x8000000000000UL - 1; ++ ++ /* now between 2^255 and 2^256-20, and offset by 2^255. */ ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[4] &= 0x7ffffffffffffUL; ++ ++ store_limb(output, t[0] | (t[1] << 51)); ++ store_limb(output+8, (t[1] >> 13) | (t[2] << 38)); ++ store_limb(output+16, (t[2] >> 26) | (t[3] << 25)); ++ store_limb(output+24, (t[3] >> 39) | (t[4] << 12)); ++} ++ ++/* Input: Q, Q', Q-Q' ++ * Output: 2Q, Q+Q' ++ * ++ * x2 z3: long form ++ * x3 z3: long form ++ * x z: short form, destroyed ++ * xprime zprime: short form, destroyed ++ * qmqp: short form, preserved ++ */ ++static void fmonty(limb *x2, limb *z2, /* output 2Q */ ++ limb *x3, limb *z3, /* output Q + Q' */ ++ limb *x, limb *z, /* input Q */ ++ limb *xprime, limb *zprime, /* input Q' */ ++ const limb *qmqp /* input Q - Q' */) ++{ ++ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], zzprime[5], zzzprime[5]; ++ ++ memcpy(origx, x, 5 * sizeof(limb)); ++ fsum(x, z); ++ fdifference_backwards(z, origx); // does x - z ++ ++ memcpy(origxprime, xprime, sizeof(limb) * 5); ++ fsum(xprime, zprime); ++ fdifference_backwards(zprime, origxprime); ++ fmul(xxprime, xprime, z); ++ fmul(zzprime, x, zprime); ++ memcpy(origxprime, xxprime, sizeof(limb) * 5); ++ fsum(xxprime, zzprime); ++ fdifference_backwards(zzprime, origxprime); ++ fsquare_times(x3, xxprime, 1); ++ fsquare_times(zzzprime, zzprime, 1); ++ fmul(z3, zzzprime, qmqp); ++ ++ fsquare_times(xx, x, 1); ++ fsquare_times(zz, z, 1); ++ fmul(x2, xx, zz); ++ fdifference_backwards(zz, xx); // does zz = xx - zz ++ fscalar_product(zzz, zz, 121665); ++ fsum(zzz, xx); ++ fmul(z2, zz, zzz); ++} ++ ++/* Maybe swap the contents of two limb arrays (@a and @b), each @len elements ++ * long. Perform the swap iff @swap is non-zero. ++ * ++ * This function performs the swap without leaking any side-channel ++ * information. ++ */ ++static void swap_conditional(limb a[5], limb b[5], limb iswap) ++{ ++ unsigned i; ++ const limb swap = -iswap; ++ ++ for (i = 0; i < 5; ++i) { ++ const limb x = swap & (a[i] ^ b[i]); ++ a[i] ^= x; ++ b[i] ^= x; ++ } ++} ++ ++/* Calculates nQ where Q is the x-coordinate of a point on the curve ++ * ++ * resultx/resultz: the x coordinate of the resulting curve point (short form) ++ * n: a little endian, 32-byte number ++ * q: a point of the curve (short form) ++ */ ++static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) ++{ ++ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0}; ++ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; ++ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1}; ++ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; ++ ++ unsigned i, j; ++ ++ memcpy(nqpqx, q, sizeof(limb) * 5); ++ ++ for (i = 0; i < 32; ++i) { ++ u8 byte = n[31 - i]; ++ for (j = 0; j < 8; ++j) { ++ const limb bit = byte >> 7; ++ ++ swap_conditional(nqx, nqpqx, bit); ++ swap_conditional(nqz, nqpqz, bit); ++ fmonty(nqx2, nqz2, ++ nqpqx2, nqpqz2, ++ nqx, nqz, ++ nqpqx, nqpqz, ++ q); ++ swap_conditional(nqx2, nqpqx2, bit); ++ swap_conditional(nqz2, nqpqz2, bit); ++ ++ t = nqx; ++ nqx = nqx2; ++ nqx2 = t; ++ t = nqz; ++ nqz = nqz2; ++ nqz2 = t; ++ t = nqpqx; ++ nqpqx = nqpqx2; ++ nqpqx2 = t; ++ t = nqpqz; ++ nqpqz = nqpqz2; ++ nqpqz2 = t; ++ ++ byte <<= 1; ++ } ++ } ++ ++ memcpy(resultx, nqx, sizeof(limb) * 5); ++ memcpy(resultz, nqz, sizeof(limb) * 5); ++} ++ ++static void crecip(felem out, const felem z) ++{ ++ felem a,t0,b,c; ++ ++ /* 2 */ fsquare_times(a, z, 1); // a = 2 ++ /* 8 */ fsquare_times(t0, a, 2); ++ /* 9 */ fmul(b, t0, z); // b = 9 ++ /* 11 */ fmul(a, b, a); // a = 11 ++ /* 22 */ fsquare_times(t0, a, 1); ++ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b); ++ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5); ++ /* 2^10 - 2^0 */ fmul(b, t0, b); ++ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10); ++ /* 2^20 - 2^0 */ fmul(c, t0, b); ++ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20); ++ /* 2^40 - 2^0 */ fmul(t0, t0, c); ++ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10); ++ /* 2^50 - 2^0 */ fmul(b, t0, b); ++ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50); ++ /* 2^100 - 2^0 */ fmul(c, t0, b); ++ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100); ++ /* 2^200 - 2^0 */ fmul(t0, t0, c); ++ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50); ++ /* 2^250 - 2^0 */ fmul(t0, t0, b); ++ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5); ++ /* 2^255 - 21 */ fmul(out, t0, a); ++} ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]) ++{ ++ limb bp[5], x[5], z[5], zmone[5]; ++ u8 e[32]; ++ ++ memcpy(e, secret, 32); ++ normalize_secret(e); ++ ++ fexpand(bp, basepoint); ++ cmult(x, z, e, bp); ++ crecip(zmone, z); ++ fmul(z, x, zmone); ++ fcontract(mypublic, z); ++ ++ memzero_explicit(e, sizeof(e)); ++ memzero_explicit(bp, sizeof(bp)); ++ memzero_explicit(x, sizeof(x)); ++ memzero_explicit(z, sizeof(z)); ++ memzero_explicit(zmone, sizeof(zmone)); ++} ++ ++#else ++typedef s64 limb; ++ ++/* Field element representation: ++ * ++ * Field elements are written as an array of signed, 64-bit limbs, least ++ * significant first. The value of the field element is: ++ * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... ++ * ++ * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ ++ ++/* Sum two numbers: output += in */ ++static void fsum(limb *output, const limb *in) ++{ ++ unsigned i; ++ for (i = 0; i < 10; i += 2) { ++ output[0 + i] = output[0 + i] + in[0 + i]; ++ output[1 + i] = output[1 + i] + in[1 + i]; ++ } ++} ++ ++/* Find the difference of two numbers: output = in - output ++ * (note the order of the arguments!). */ ++static void fdifference(limb *output, const limb *in) ++{ ++ unsigned i; ++ for (i = 0; i < 10; ++i) ++ output[i] = in[i] - output[i]; ++} ++ ++/* Multiply a number by a scalar: output = in * scalar */ ++static void fscalar_product(limb *output, const limb *in, const limb scalar) ++{ ++ unsigned i; ++ for (i = 0; i < 10; ++i) ++ output[i] = in[i] * scalar; ++} ++ ++/* Multiply two numbers: output = in2 * in ++ * ++ * output must be distinct to both inputs. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * output[x] <= 14 * the largest product of the input limbs. */ ++static void fproduct(limb *output, const limb *in2, const limb *in) ++{ ++ output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); ++ output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[0]); ++ output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[0]); ++ output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[0]); ++ output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + ++ 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[0])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[0]); ++ output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[0]); ++ output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[2])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[0]); ++ output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[0]); ++ output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + ++ 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[2])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[0]); ++ output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[0]); ++ output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[4])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[2]); ++ output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[2]); ++ output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + ++ 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[3])) + ++ ((limb) ((s32) in2[4])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[4]); ++ output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[4]); ++ output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[5])) + ++ ((limb) ((s32) in2[6])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[6]); ++ output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[6]); ++ output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[7])); ++ output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[8]); ++ output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); ++} ++ ++/* Reduce a long form to a short form by taking the input mod 2^255 - 19. ++ * ++ * On entry: |output[i]| < 14*2^54 ++ * On exit: |output[0..8]| < 280*2^54 */ ++static void freduce_degree(limb *output) ++{ ++ /* Each of these shifts and adds ends up multiplying the value by 19. ++ * ++ * For output[0..8], the absolute entry value is < 14*2^54 and we add, at ++ * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ ++ output[8] += output[18] << 4; ++ output[8] += output[18] << 1; ++ output[8] += output[18]; ++ output[7] += output[17] << 4; ++ output[7] += output[17] << 1; ++ output[7] += output[17]; ++ output[6] += output[16] << 4; ++ output[6] += output[16] << 1; ++ output[6] += output[16]; ++ output[5] += output[15] << 4; ++ output[5] += output[15] << 1; ++ output[5] += output[15]; ++ output[4] += output[14] << 4; ++ output[4] += output[14] << 1; ++ output[4] += output[14]; ++ output[3] += output[13] << 4; ++ output[3] += output[13] << 1; ++ output[3] += output[13]; ++ output[2] += output[12] << 4; ++ output[2] += output[12] << 1; ++ output[2] += output[12]; ++ output[1] += output[11] << 4; ++ output[1] += output[11] << 1; ++ output[1] += output[11]; ++ output[0] += output[10] << 4; ++ output[0] += output[10] << 1; ++ output[0] += output[10]; ++} ++ ++#if (-1 & 3) != 3 ++#error "This code only works on a two's complement system" ++#endif ++ ++/* return v / 2^26, using only shifts and adds. ++ * ++ * On entry: v can take any value. */ ++static inline limb div_by_2_26(const limb v) ++{ ++ /* High word of v; no shift needed. */ ++ const u32 highword = (u32) (((u64) v) >> 32); ++ /* Set to all 1s if v was negative; else set to 0s. */ ++ const s32 sign = ((s32) highword) >> 31; ++ /* Set to 0x3ffffff if v was negative; else set to 0. */ ++ const s32 roundoff = ((u32) sign) >> 6; ++ /* Should return v / (1<<26) */ ++ return (v + roundoff) >> 26; ++} ++ ++/* return v / (2^25), using only shifts and adds. ++ * ++ * On entry: v can take any value. */ ++static inline limb div_by_2_25(const limb v) ++{ ++ /* High word of v; no shift needed*/ ++ const u32 highword = (u32) (((u64) v) >> 32); ++ /* Set to all 1s if v was negative; else set to 0s. */ ++ const s32 sign = ((s32) highword) >> 31; ++ /* Set to 0x1ffffff if v was negative; else set to 0. */ ++ const s32 roundoff = ((u32) sign) >> 7; ++ /* Should return v / (1<<25) */ ++ return (v + roundoff) >> 25; ++} ++ ++/* Reduce all coefficients of the short form input so that |x| < 2^26. ++ * ++ * On entry: |output[i]| < 280*2^54 */ ++static void freduce_coefficients(limb *output) ++{ ++ unsigned i; ++ ++ output[10] = 0; ++ ++ for (i = 0; i < 10; i += 2) { ++ limb over = div_by_2_26(output[i]); ++ /* The entry condition (that |output[i]| < 280*2^54) means that over is, at ++ * most, 280*2^28 in the first iteration of this loop. This is added to the ++ * next limb and we can approximate the resulting bound of that limb by ++ * 281*2^54. */ ++ output[i] -= over << 26; ++ output[i+1] += over; ++ ++ /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < ++ * 281*2^29. When this is added to the next limb, the resulting bound can ++ * be approximated as 281*2^54. ++ * ++ * For subsequent iterations of the loop, 281*2^54 remains a conservative ++ * bound and no overflow occurs. */ ++ over = div_by_2_25(output[i+1]); ++ output[i+1] -= over << 25; ++ output[i+2] += over; ++ } ++ /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ ++ output[0] += output[10] << 4; ++ output[0] += output[10] << 1; ++ output[0] += output[10]; ++ ++ output[10] = 0; ++ ++ /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 ++ * So |over| will be no more than 2^16. */ ++ { ++ limb over = div_by_2_26(output[0]); ++ output[0] -= over << 26; ++ output[1] += over; ++ } ++ ++ /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The ++ * bound on |output[1]| is sufficient to meet our needs. */ ++} ++ ++/* A helpful wrapper around fproduct: output = in * in2. ++ * ++ * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. ++ * ++ * output must be distinct to both inputs. The output is reduced degree ++ * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ ++static void fmul(limb *output, const limb *in, const limb *in2) ++{ ++ limb t[19]; ++ fproduct(t, in, in2); ++ /* |t[i]| < 14*2^54 */ ++ freduce_degree(t); ++ freduce_coefficients(t); ++ /* |t[i]| < 2^26 */ ++ memcpy(output, t, sizeof(limb) * 10); ++} ++ ++/* Square a number: output = in**2 ++ * ++ * output must be distinct from the input. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * output[x] <= 14 * the largest product of the input limbs. */ ++static void fsquare_inner(limb *output, const limb *in) ++{ ++ output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); ++ output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); ++ output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + ++ ((limb) ((s32) in[0])) * ((s32) in[2])); ++ output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + ++ ((limb) ((s32) in[0])) * ((s32) in[3])); ++ output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + ++ 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + ++ 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); ++ output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + ++ ((limb) ((s32) in[1])) * ((s32) in[4]) + ++ ((limb) ((s32) in[0])) * ((s32) in[5])); ++ output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + ++ ((limb) ((s32) in[2])) * ((s32) in[4]) + ++ ((limb) ((s32) in[0])) * ((s32) in[6]) + ++ 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); ++ output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + ++ ((limb) ((s32) in[2])) * ((s32) in[5]) + ++ ((limb) ((s32) in[1])) * ((s32) in[6]) + ++ ((limb) ((s32) in[0])) * ((s32) in[7])); ++ output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + ++ 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + ++ ((limb) ((s32) in[0])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[5]))); ++ output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + ++ ((limb) ((s32) in[3])) * ((s32) in[6]) + ++ ((limb) ((s32) in[2])) * ((s32) in[7]) + ++ ((limb) ((s32) in[1])) * ((s32) in[8]) + ++ ((limb) ((s32) in[0])) * ((s32) in[9])); ++ output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + ++ ((limb) ((s32) in[4])) * ((s32) in[6]) + ++ ((limb) ((s32) in[2])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + ++ ((limb) ((s32) in[1])) * ((s32) in[9]))); ++ output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + ++ ((limb) ((s32) in[4])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[8]) + ++ ((limb) ((s32) in[2])) * ((s32) in[9])); ++ output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + ++ 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[9]))); ++ output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + ++ ((limb) ((s32) in[5])) * ((s32) in[8]) + ++ ((limb) ((s32) in[4])) * ((s32) in[9])); ++ output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + ++ ((limb) ((s32) in[6])) * ((s32) in[8]) + ++ 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); ++ output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + ++ ((limb) ((s32) in[6])) * ((s32) in[9])); ++ output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + ++ 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); ++ output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); ++ output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); ++} ++ ++/* fsquare sets output = in^2. ++ * ++ * On entry: The |in| argument is in reduced coefficients form and |in[i]| < ++ * 2^27. ++ * ++ * On exit: The |output| argument is in reduced coefficients form (indeed, one ++ * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ ++static void fsquare(limb *output, const limb *in) ++{ ++ limb t[19]; ++ fsquare_inner(t, in); ++ /* |t[i]| < 14*2^54 because the largest product of two limbs will be < ++ * 2^(27+27) and fsquare_inner adds together, at most, 14 of those ++ * products. */ ++ freduce_degree(t); ++ freduce_coefficients(t); ++ /* |t[i]| < 2^26 */ ++ memcpy(output, t, sizeof(limb) * 10); ++} ++ ++/* Take a little-endian, 32-byte number and expand it into polynomial form */ ++static inline void fexpand(limb *output, const u8 *input) ++{ ++#define F(n,start,shift,mask) \ ++ output[n] = ((((limb) input[start + 0]) | \ ++ ((limb) input[start + 1]) << 8 | \ ++ ((limb) input[start + 2]) << 16 | \ ++ ((limb) input[start + 3]) << 24) >> shift) & mask; ++ F(0, 0, 0, 0x3ffffff); ++ F(1, 3, 2, 0x1ffffff); ++ F(2, 6, 3, 0x3ffffff); ++ F(3, 9, 5, 0x1ffffff); ++ F(4, 12, 6, 0x3ffffff); ++ F(5, 16, 0, 0x1ffffff); ++ F(6, 19, 1, 0x3ffffff); ++ F(7, 22, 3, 0x1ffffff); ++ F(8, 25, 4, 0x3ffffff); ++ F(9, 28, 6, 0x1ffffff); ++#undef F ++} ++ ++#if (-32 >> 1) != -16 ++#error "This code only works when >> does sign-extension on negative numbers" ++#endif ++ ++/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ ++static s32 s32_eq(s32 a, s32 b) ++{ ++ a = ~(a ^ b); ++ a &= a << 16; ++ a &= a << 8; ++ a &= a << 4; ++ a &= a << 2; ++ a &= a << 1; ++ return a >> 31; ++} ++ ++/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are ++ * both non-negative. */ ++static s32 s32_gte(s32 a, s32 b) ++{ ++ a -= b; ++ /* a >= 0 iff a >= b. */ ++ return ~(a >> 31); ++} ++ ++/* Take a fully reduced polynomial form number and contract it into a ++ * little-endian, 32-byte array. ++ * ++ * On entry: |input_limbs[i]| < 2^26 */ ++static void fcontract(u8 *output, limb *input_limbs) ++{ ++ int i; ++ int j; ++ s32 input[10]; ++ s32 mask; ++ ++ /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ ++ for (i = 0; i < 10; i++) { ++ input[i] = input_limbs[i]; ++ } ++ ++ for (j = 0; j < 2; ++j) { ++ for (i = 0; i < 9; ++i) { ++ if ((i & 1) == 1) { ++ /* This calculation is a time-invariant way to make input[i] ++ * non-negative by borrowing from the next-larger limb. */ ++ const s32 mask = input[i] >> 31; ++ const s32 carry = -((input[i] & mask) >> 25); ++ input[i] = input[i] + (carry << 25); ++ input[i+1] = input[i+1] - carry; ++ } else { ++ const s32 mask = input[i] >> 31; ++ const s32 carry = -((input[i] & mask) >> 26); ++ input[i] = input[i] + (carry << 26); ++ input[i+1] = input[i+1] - carry; ++ } ++ } ++ ++ /* There's no greater limb for input[9] to borrow from, but we can multiply ++ * by 19 and borrow from input[0], which is valid mod 2^255-19. */ ++ { ++ const s32 mask = input[9] >> 31; ++ const s32 carry = -((input[9] & mask) >> 25); ++ input[9] = input[9] + (carry << 25); ++ input[0] = input[0] - (carry * 19); ++ } ++ ++ /* After the first iteration, input[1..9] are non-negative and fit within ++ * 25 or 26 bits, depending on position. However, input[0] may be ++ * negative. */ ++ } ++ ++ /* The first borrow-propagation pass above ended with every limb ++ except (possibly) input[0] non-negative. ++ If input[0] was negative after the first pass, then it was because of a ++ carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, ++ one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. ++ In the second pass, each limb is decreased by at most one. Thus the second ++ borrow-propagation pass could only have wrapped around to decrease ++ input[0] again if the first pass left input[0] negative *and* input[1] ++ through input[9] were all zero. In that case, input[1] is now 2^25 - 1, ++ and this last borrow-propagation step will leave input[1] non-negative. */ ++ { ++ const s32 mask = input[0] >> 31; ++ const s32 carry = -((input[0] & mask) >> 26); ++ input[0] = input[0] + (carry << 26); ++ input[1] = input[1] - carry; ++ } ++ ++ /* All input[i] are now non-negative. However, there might be values between ++ * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ ++ for (j = 0; j < 2; j++) { ++ for (i = 0; i < 9; i++) { ++ if ((i & 1) == 1) { ++ const s32 carry = input[i] >> 25; ++ input[i] &= 0x1ffffff; ++ input[i+1] += carry; ++ } else { ++ const s32 carry = input[i] >> 26; ++ input[i] &= 0x3ffffff; ++ input[i+1] += carry; ++ } ++ } ++ ++ { ++ const s32 carry = input[9] >> 25; ++ input[9] &= 0x1ffffff; ++ input[0] += 19*carry; ++ } ++ } ++ ++ /* If the first carry-chain pass, just above, ended up with a carry from ++ * input[9], and that caused input[0] to be out-of-bounds, then input[0] was ++ * < 2^26 + 2*19, because the carry was, at most, two. ++ * ++ * If the second pass carried from input[9] again then input[0] is < 2*19 and ++ * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ ++ ++ /* It still remains the case that input might be between 2^255-19 and 2^255. ++ * In this case, input[1..9] must take their maximum value and input[0] must ++ * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ ++ mask = s32_gte(input[0], 0x3ffffed); ++ for (i = 1; i < 10; i++) { ++ if ((i & 1) == 1) { ++ mask &= s32_eq(input[i], 0x1ffffff); ++ } else { ++ mask &= s32_eq(input[i], 0x3ffffff); ++ } ++ } ++ ++ /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus ++ * this conditionally subtracts 2^255-19. */ ++ input[0] -= mask & 0x3ffffed; ++ ++ for (i = 1; i < 10; i++) { ++ if ((i & 1) == 1) { ++ input[i] -= mask & 0x1ffffff; ++ } else { ++ input[i] -= mask & 0x3ffffff; ++ } ++ } ++ ++ input[1] <<= 2; ++ input[2] <<= 3; ++ input[3] <<= 5; ++ input[4] <<= 6; ++ input[6] <<= 1; ++ input[7] <<= 3; ++ input[8] <<= 4; ++ input[9] <<= 6; ++#define F(i, s) \ ++ output[s+0] |= input[i] & 0xff; \ ++ output[s+1] = (input[i] >> 8) & 0xff; \ ++ output[s+2] = (input[i] >> 16) & 0xff; \ ++ output[s+3] = (input[i] >> 24) & 0xff; ++ output[0] = 0; ++ output[16] = 0; ++ F(0,0); ++ F(1,3); ++ F(2,6); ++ F(3,9); ++ F(4,12); ++ F(5,16); ++ F(6,19); ++ F(7,22); ++ F(8,25); ++ F(9,28); ++#undef F ++} ++ ++/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave ++ * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid ++ * side-channel attacks. ++ * ++ * NOTE that this function requires that 'iswap' be 1 or 0; other values give ++ * wrong results. Also, the two limb arrays must be in reduced-coefficient, ++ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, ++ * and all all values in a[0..9],b[0..9] must have magnitude less than ++ * INT32_MAX. */ ++static void swap_conditional(limb a[19], limb b[19], limb iswap) ++{ ++ unsigned i; ++ const s32 swap = (s32) -iswap; ++ ++ for (i = 0; i < 10; ++i) { ++ const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); ++ a[i] = ((s32)a[i]) ^ x; ++ b[i] = ((s32)b[i]) ^ x; ++ } ++} ++ ++static void crecip(limb *out, const limb *z) ++{ ++ limb z2[10]; ++ limb z9[10]; ++ limb z11[10]; ++ limb z2_5_0[10]; ++ limb z2_10_0[10]; ++ limb z2_20_0[10]; ++ limb z2_50_0[10]; ++ limb z2_100_0[10]; ++ limb t0[10]; ++ limb t1[10]; ++ int i; ++ ++ /* 2 */ fsquare(z2,z); ++ /* 4 */ fsquare(t1,z2); ++ /* 8 */ fsquare(t0,t1); ++ /* 9 */ fmul(z9,t0,z); ++ /* 11 */ fmul(z11,z9,z2); ++ /* 22 */ fsquare(t0,z11); ++ /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); ++ ++ /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); ++ /* 2^7 - 2^2 */ fsquare(t1,t0); ++ /* 2^8 - 2^3 */ fsquare(t0,t1); ++ /* 2^9 - 2^4 */ fsquare(t1,t0); ++ /* 2^10 - 2^5 */ fsquare(t0,t1); ++ /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); ++ ++ /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); ++ /* 2^12 - 2^2 */ fsquare(t1,t0); ++ /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); ++ ++ /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); ++ /* 2^22 - 2^2 */ fsquare(t1,t0); ++ /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); ++ ++ /* 2^41 - 2^1 */ fsquare(t1,t0); ++ /* 2^42 - 2^2 */ fsquare(t0,t1); ++ /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t1,t0); fsquare(t0,t1); } ++ /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); ++ ++ /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); ++ /* 2^52 - 2^2 */ fsquare(t1,t0); ++ /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); ++ ++ /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); ++ /* 2^102 - 2^2 */ fsquare(t0,t1); ++ /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { fsquare(t1,t0); fsquare(t0,t1); } ++ /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); ++ ++ /* 2^201 - 2^1 */ fsquare(t0,t1); ++ /* 2^202 - 2^2 */ fsquare(t1,t0); ++ /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); ++ ++ /* 2^251 - 2^1 */ fsquare(t1,t0); ++ /* 2^252 - 2^2 */ fsquare(t0,t1); ++ /* 2^253 - 2^3 */ fsquare(t1,t0); ++ /* 2^254 - 2^4 */ fsquare(t0,t1); ++ /* 2^255 - 2^5 */ fsquare(t1,t0); ++ /* 2^255 - 21 */ fmul(out,t1,z11); ++} ++ ++ ++/* Input: Q, Q', Q-Q' ++ * Output: 2Q, Q+Q' ++ * ++ * x2 z3: long form ++ * x3 z3: long form ++ * x z: short form, destroyed ++ * xprime zprime: short form, destroyed ++ * qmqp: short form, preserved ++ * ++ * On entry and exit, the absolute value of the limbs of all inputs and outputs ++ * are < 2^26. */ ++static void fmonty(limb *x2, limb *z2, /* output 2Q */ ++ limb *x3, limb *z3, /* output Q + Q' */ ++ limb *x, limb *z, /* input Q */ ++ limb *xprime, limb *zprime, /* input Q' */ ++ const limb *qmqp /* input Q - Q' */) ++{ ++ limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], ++ zzprime[19], zzzprime[19], xxxprime[19]; ++ ++ memcpy(origx, x, 10 * sizeof(limb)); ++ fsum(x, z); ++ /* |x[i]| < 2^27 */ ++ fdifference(z, origx); /* does x - z */ ++ /* |z[i]| < 2^27 */ ++ ++ memcpy(origxprime, xprime, sizeof(limb) * 10); ++ fsum(xprime, zprime); ++ /* |xprime[i]| < 2^27 */ ++ fdifference(zprime, origxprime); ++ /* |zprime[i]| < 2^27 */ ++ fproduct(xxprime, xprime, z); ++ /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < ++ * 2^(27+27) and fproduct adds together, at most, 14 of those products. ++ * (Approximating that to 2^58 doesn't work out.) */ ++ fproduct(zzprime, x, zprime); ++ /* |zzprime[i]| < 14*2^54 */ ++ freduce_degree(xxprime); ++ freduce_coefficients(xxprime); ++ /* |xxprime[i]| < 2^26 */ ++ freduce_degree(zzprime); ++ freduce_coefficients(zzprime); ++ /* |zzprime[i]| < 2^26 */ ++ memcpy(origxprime, xxprime, sizeof(limb) * 10); ++ fsum(xxprime, zzprime); ++ /* |xxprime[i]| < 2^27 */ ++ fdifference(zzprime, origxprime); ++ /* |zzprime[i]| < 2^27 */ ++ fsquare(xxxprime, xxprime); ++ /* |xxxprime[i]| < 2^26 */ ++ fsquare(zzzprime, zzprime); ++ /* |zzzprime[i]| < 2^26 */ ++ fproduct(zzprime, zzzprime, qmqp); ++ /* |zzprime[i]| < 14*2^52 */ ++ freduce_degree(zzprime); ++ freduce_coefficients(zzprime); ++ /* |zzprime[i]| < 2^26 */ ++ memcpy(x3, xxxprime, sizeof(limb) * 10); ++ memcpy(z3, zzprime, sizeof(limb) * 10); ++ ++ fsquare(xx, x); ++ /* |xx[i]| < 2^26 */ ++ fsquare(zz, z); ++ /* |zz[i]| < 2^26 */ ++ fproduct(x2, xx, zz); ++ /* |x2[i]| < 14*2^52 */ ++ freduce_degree(x2); ++ freduce_coefficients(x2); ++ /* |x2[i]| < 2^26 */ ++ fdifference(zz, xx); // does zz = xx - zz ++ /* |zz[i]| < 2^27 */ ++ memset(zzz + 10, 0, sizeof(limb) * 9); ++ fscalar_product(zzz, zz, 121665); ++ /* |zzz[i]| < 2^(27+17) */ ++ /* No need to call freduce_degree here: ++ fscalar_product doesn't increase the degree of its input. */ ++ freduce_coefficients(zzz); ++ /* |zzz[i]| < 2^26 */ ++ fsum(zzz, xx); ++ /* |zzz[i]| < 2^27 */ ++ fproduct(z2, zz, zzz); ++ /* |z2[i]| < 14*2^(26+27) */ ++ freduce_degree(z2); ++ freduce_coefficients(z2); ++ /* |z2|i| < 2^26 */ ++} ++ ++/* Calculates nQ where Q is the x-coordinate of a point on the curve ++ * ++ * resultx/resultz: the x coordinate of the resulting curve point (short form) ++ * n: a little endian, 32-byte number ++ * q: a point of the curve (short form) */ ++static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) ++{ ++ limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; ++ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; ++ limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; ++ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; ++ ++ unsigned i, j; ++ ++ memcpy(nqpqx, q, sizeof(limb) * 10); ++ ++ for (i = 0; i < 32; ++i) { ++ u8 byte = n[31 - i]; ++ for (j = 0; j < 8; ++j) { ++ const limb bit = byte >> 7; ++ ++ swap_conditional(nqx, nqpqx, bit); ++ swap_conditional(nqz, nqpqz, bit); ++ fmonty(nqx2, nqz2, ++ nqpqx2, nqpqz2, ++ nqx, nqz, ++ nqpqx, nqpqz, ++ q); ++ swap_conditional(nqx2, nqpqx2, bit); ++ swap_conditional(nqz2, nqpqz2, bit); ++ ++ t = nqx; ++ nqx = nqx2; ++ nqx2 = t; ++ t = nqz; ++ nqz = nqz2; ++ nqz2 = t; ++ t = nqpqx; ++ nqpqx = nqpqx2; ++ nqpqx2 = t; ++ t = nqpqz; ++ nqpqz = nqpqz2; ++ nqpqz2 = t; ++ ++ byte <<= 1; ++ } ++ } ++ ++ memcpy(resultx, nqx, sizeof(limb) * 10); ++ memcpy(resultz, nqz, sizeof(limb) * 10); ++} ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]) ++{ ++ limb bp[10], x[10], z[11], zmone[10]; ++ u8 e[32]; ++ ++ memcpy(e, secret, 32); ++ normalize_secret(e); ++ ++ fexpand(bp, basepoint); ++ cmult(x, z, e, bp); ++ crecip(zmone, z); ++ fmul(z, x, zmone); ++ fcontract(mypublic, z); ++ ++ memzero_explicit(e, sizeof(e)); ++ memzero_explicit(bp, sizeof(bp)); ++ memzero_explicit(x, sizeof(x)); ++ memzero_explicit(z, sizeof(z)); ++ memzero_explicit(zmone, sizeof(zmone)); ++} ++#endif ++ ++void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ get_random_bytes(secret, CURVE25519_POINT_SIZE); ++ normalize_secret(secret); ++} ++ ++void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ static const u8 basepoint[CURVE25519_POINT_SIZE] = { 9 }; ++ curve25519(pub, secret, basepoint); ++} ++ ++#include "../selftest/curve25519.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/blake2s.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,36 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef BLAKE2S_H ++#define BLAKE2S_H ++ ++#include ++ ++enum blake2s_lengths { ++ BLAKE2S_BLOCKBYTES = 64, ++ BLAKE2S_OUTBYTES = 32, ++ BLAKE2S_KEYBYTES = 32 ++}; ++ ++struct blake2s_state { ++ u32 h[8]; ++ u32 t[2]; ++ u32 f[2]; ++ u8 buf[2 * BLAKE2S_BLOCKBYTES]; ++ size_t buflen; ++ u8 last_node; ++}; ++ ++void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u8 keylen); ++ ++void blake2s_init(struct blake2s_state *state, const u8 outlen); ++void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen); ++void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen); ++void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen); ++ ++void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen); ++ ++#ifdef DEBUG ++bool blake2s_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20poly1305.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,78 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef CHACHA20POLY1305_H ++#define CHACHA20POLY1305_H ++ ++#include ++ ++struct scatterlist; ++ ++enum chacha20poly1305_lengths { ++ XCHACHA20POLY1305_NONCELEN = 24, ++ CHACHA20POLY1305_KEYLEN = 32, ++ CHACHA20POLY1305_AUTHTAGLEN = 16 ++}; ++ ++void chacha20poly1305_init(void); ++ ++bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN], ++ bool have_simd); ++ ++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++#ifdef CONFIG_X86_64 ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#include ++#else ++#include ++#endif ++#endif ++ ++static inline bool chacha20poly1305_init_simd(void) ++{ ++ bool have_simd = false; ++#ifdef CONFIG_X86_64 ++ have_simd = irq_fpu_usable(); ++ if (have_simd) ++ kernel_fpu_begin(); ++#endif ++ return have_simd; ++} ++ ++static inline void chacha20poly1305_deinit_simd(bool was_on) ++{ ++#ifdef CONFIG_X86_64 ++ if (was_on) ++ kernel_fpu_end(); ++#endif ++} ++ ++#ifdef DEBUG ++bool chacha20poly1305_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/curve25519.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,20 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef CURVE25519_H ++#define CURVE25519_H ++ ++#include ++ ++enum curve25519_lengths { ++ CURVE25519_POINT_SIZE = 32 ++}; ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]); ++void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE]); ++void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE]); ++ ++#ifdef DEBUG ++bool curve25519_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20-avx2-x86_64.S 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,443 @@ ++/* ++ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 AVX2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 32 ++ ++ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003 ++ .octa 0x0e0d0c0f0a09080b0605040702010003 ++ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302 ++ .octa 0x0d0c0f0e09080b0a0504070601000302 ++CTRINC: .octa 0x00000003000000020000000100000000 ++ .octa 0x00000007000000060000000500000004 ++ ++.text ++ ++ENTRY(chacha20_asm_8block_xor_avx2) ++ # %rdi: Input state matrix, s ++ # %rsi: 8 data blocks output, o ++ # %rdx: 8 data blocks input, i ++ ++ # This function encrypts eight consecutive ChaCha20 blocks by loading ++ # the state matrix in AVX registers eight times. As we need some ++ # scratch registers, we save the first four registers on the stack. The ++ # algorithm performs each operation on the corresponding word of each ++ # state matrix, hence requires no word shuffling. For final XORing step ++ # we transpose the matrix by interleaving 32-, 64- and then 128-bit ++ # words, which allows us to do XOR in AVX registers. 8/16-bit word ++ # rotation is done with the slightly better performing byte shuffling, ++ # 7/12-bit word rotation uses traditional shift+OR. ++ ++ vzeroupper ++ # 4 * 32 byte stack, 32-byte aligned ++ mov %rsp, %r8 ++ and $~31, %rsp ++ sub $0x80, %rsp ++ ++ # x0..15[0-7] = s[0..15] ++ vpbroadcastd 0x00(%rdi),%ymm0 ++ vpbroadcastd 0x04(%rdi),%ymm1 ++ vpbroadcastd 0x08(%rdi),%ymm2 ++ vpbroadcastd 0x0c(%rdi),%ymm3 ++ vpbroadcastd 0x10(%rdi),%ymm4 ++ vpbroadcastd 0x14(%rdi),%ymm5 ++ vpbroadcastd 0x18(%rdi),%ymm6 ++ vpbroadcastd 0x1c(%rdi),%ymm7 ++ vpbroadcastd 0x20(%rdi),%ymm8 ++ vpbroadcastd 0x24(%rdi),%ymm9 ++ vpbroadcastd 0x28(%rdi),%ymm10 ++ vpbroadcastd 0x2c(%rdi),%ymm11 ++ vpbroadcastd 0x30(%rdi),%ymm12 ++ vpbroadcastd 0x34(%rdi),%ymm13 ++ vpbroadcastd 0x38(%rdi),%ymm14 ++ vpbroadcastd 0x3c(%rdi),%ymm15 ++ # x0..3 on stack ++ vmovdqa %ymm0,0x00(%rsp) ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa %ymm3,0x60(%rsp) ++ ++ vmovdqa CTRINC(%rip),%ymm1 ++ vmovdqa ROT8(%rip),%ymm2 ++ vmovdqa ROT16(%rip),%ymm3 ++ ++ # x12 += counter values 0-3 ++ vpaddd %ymm1,%ymm12,%ymm12 ++ ++ mov $10,%ecx ++ ++.Ldoubleround8: ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 16) ++ vpaddd 0x00(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm3,%ymm12,%ymm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 16) ++ vpaddd 0x20(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm3,%ymm13,%ymm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 16) ++ vpaddd 0x40(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm3,%ymm14,%ymm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 16) ++ vpaddd 0x60(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm3,%ymm15,%ymm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 12) ++ vpaddd %ymm12,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm4,%ymm4 ++ vpslld $12,%ymm4,%ymm0 ++ vpsrld $20,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 12) ++ vpaddd %ymm13,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm5,%ymm5 ++ vpslld $12,%ymm5,%ymm0 ++ vpsrld $20,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 12) ++ vpaddd %ymm14,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm6,%ymm6 ++ vpslld $12,%ymm6,%ymm0 ++ vpsrld $20,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 12) ++ vpaddd %ymm15,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm7,%ymm7 ++ vpslld $12,%ymm7,%ymm0 ++ vpsrld $20,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 8) ++ vpaddd 0x00(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm2,%ymm12,%ymm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 8) ++ vpaddd 0x20(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm2,%ymm13,%ymm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 8) ++ vpaddd 0x40(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm2,%ymm14,%ymm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 8) ++ vpaddd 0x60(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm2,%ymm15,%ymm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 7) ++ vpaddd %ymm12,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm4,%ymm4 ++ vpslld $7,%ymm4,%ymm0 ++ vpsrld $25,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 7) ++ vpaddd %ymm13,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm5,%ymm5 ++ vpslld $7,%ymm5,%ymm0 ++ vpsrld $25,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 7) ++ vpaddd %ymm14,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm6,%ymm6 ++ vpslld $7,%ymm6,%ymm0 ++ vpsrld $25,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 7) ++ vpaddd %ymm15,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm7,%ymm7 ++ vpslld $7,%ymm7,%ymm0 ++ vpsrld $25,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 16) ++ vpaddd 0x00(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm3,%ymm15,%ymm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 16)%ymm0 ++ vpaddd 0x20(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm3,%ymm12,%ymm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 16) ++ vpaddd 0x40(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm3,%ymm13,%ymm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 16) ++ vpaddd 0x60(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm3,%ymm14,%ymm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 12) ++ vpaddd %ymm15,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm5,%ymm5 ++ vpslld $12,%ymm5,%ymm0 ++ vpsrld $20,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 12) ++ vpaddd %ymm12,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm6,%ymm6 ++ vpslld $12,%ymm6,%ymm0 ++ vpsrld $20,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 12) ++ vpaddd %ymm13,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm7,%ymm7 ++ vpslld $12,%ymm7,%ymm0 ++ vpsrld $20,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 12) ++ vpaddd %ymm14,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm4,%ymm4 ++ vpslld $12,%ymm4,%ymm0 ++ vpsrld $20,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 8) ++ vpaddd 0x00(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm2,%ymm15,%ymm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 8) ++ vpaddd 0x20(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm2,%ymm12,%ymm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 8) ++ vpaddd 0x40(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm2,%ymm13,%ymm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 8) ++ vpaddd 0x60(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm2,%ymm14,%ymm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 7) ++ vpaddd %ymm15,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm5,%ymm5 ++ vpslld $7,%ymm5,%ymm0 ++ vpsrld $25,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 7) ++ vpaddd %ymm12,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm6,%ymm6 ++ vpslld $7,%ymm6,%ymm0 ++ vpsrld $25,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 7) ++ vpaddd %ymm13,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm7,%ymm7 ++ vpslld $7,%ymm7,%ymm0 ++ vpsrld $25,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 7) ++ vpaddd %ymm14,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm4,%ymm4 ++ vpslld $7,%ymm4,%ymm0 ++ vpsrld $25,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ ++ dec %ecx ++ jnz .Ldoubleround8 ++ ++ # x0..15[0-3] += s[0..15] ++ vpbroadcastd 0x00(%rdi),%ymm0 ++ vpaddd 0x00(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpbroadcastd 0x04(%rdi),%ymm0 ++ vpaddd 0x20(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpbroadcastd 0x08(%rdi),%ymm0 ++ vpaddd 0x40(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpbroadcastd 0x0c(%rdi),%ymm0 ++ vpaddd 0x60(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpbroadcastd 0x10(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm4,%ymm4 ++ vpbroadcastd 0x14(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm5,%ymm5 ++ vpbroadcastd 0x18(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm6,%ymm6 ++ vpbroadcastd 0x1c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm7,%ymm7 ++ vpbroadcastd 0x20(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm8,%ymm8 ++ vpbroadcastd 0x24(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm9,%ymm9 ++ vpbroadcastd 0x28(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm10,%ymm10 ++ vpbroadcastd 0x2c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm11,%ymm11 ++ vpbroadcastd 0x30(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm12,%ymm12 ++ vpbroadcastd 0x34(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm13,%ymm13 ++ vpbroadcastd 0x38(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm14,%ymm14 ++ vpbroadcastd 0x3c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm15,%ymm15 ++ ++ # x12 += counter values 0-3 ++ vpaddd %ymm1,%ymm12,%ymm12 ++ ++ # interleave 32-bit words in state n, n+1 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vmovdqa 0x20(%rsp),%ymm1 ++ vpunpckldq %ymm1,%ymm0,%ymm2 ++ vpunpckhdq %ymm1,%ymm0,%ymm1 ++ vmovdqa %ymm2,0x00(%rsp) ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vmovdqa 0x60(%rsp),%ymm1 ++ vpunpckldq %ymm1,%ymm0,%ymm2 ++ vpunpckhdq %ymm1,%ymm0,%ymm1 ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa %ymm1,0x60(%rsp) ++ vmovdqa %ymm4,%ymm0 ++ vpunpckldq %ymm5,%ymm0,%ymm4 ++ vpunpckhdq %ymm5,%ymm0,%ymm5 ++ vmovdqa %ymm6,%ymm0 ++ vpunpckldq %ymm7,%ymm0,%ymm6 ++ vpunpckhdq %ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm8,%ymm0 ++ vpunpckldq %ymm9,%ymm0,%ymm8 ++ vpunpckhdq %ymm9,%ymm0,%ymm9 ++ vmovdqa %ymm10,%ymm0 ++ vpunpckldq %ymm11,%ymm0,%ymm10 ++ vpunpckhdq %ymm11,%ymm0,%ymm11 ++ vmovdqa %ymm12,%ymm0 ++ vpunpckldq %ymm13,%ymm0,%ymm12 ++ vpunpckhdq %ymm13,%ymm0,%ymm13 ++ vmovdqa %ymm14,%ymm0 ++ vpunpckldq %ymm15,%ymm0,%ymm14 ++ vpunpckhdq %ymm15,%ymm0,%ymm15 ++ ++ # interleave 64-bit words in state n, n+2 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vmovdqa 0x40(%rsp),%ymm2 ++ vpunpcklqdq %ymm2,%ymm0,%ymm1 ++ vpunpckhqdq %ymm2,%ymm0,%ymm2 ++ vmovdqa %ymm1,0x00(%rsp) ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vmovdqa 0x60(%rsp),%ymm2 ++ vpunpcklqdq %ymm2,%ymm0,%ymm1 ++ vpunpckhqdq %ymm2,%ymm0,%ymm2 ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa %ymm2,0x60(%rsp) ++ vmovdqa %ymm4,%ymm0 ++ vpunpcklqdq %ymm6,%ymm0,%ymm4 ++ vpunpckhqdq %ymm6,%ymm0,%ymm6 ++ vmovdqa %ymm5,%ymm0 ++ vpunpcklqdq %ymm7,%ymm0,%ymm5 ++ vpunpckhqdq %ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm8,%ymm0 ++ vpunpcklqdq %ymm10,%ymm0,%ymm8 ++ vpunpckhqdq %ymm10,%ymm0,%ymm10 ++ vmovdqa %ymm9,%ymm0 ++ vpunpcklqdq %ymm11,%ymm0,%ymm9 ++ vpunpckhqdq %ymm11,%ymm0,%ymm11 ++ vmovdqa %ymm12,%ymm0 ++ vpunpcklqdq %ymm14,%ymm0,%ymm12 ++ vpunpckhqdq %ymm14,%ymm0,%ymm14 ++ vmovdqa %ymm13,%ymm0 ++ vpunpcklqdq %ymm15,%ymm0,%ymm13 ++ vpunpckhqdq %ymm15,%ymm0,%ymm15 ++ ++ # interleave 128-bit words in state n, n+4 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm4,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm4,%ymm0,%ymm4 ++ vmovdqa %ymm1,0x00(%rsp) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm5,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm5,%ymm0,%ymm5 ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm6,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm6,%ymm0,%ymm6 ++ vmovdqa %ymm1,0x40(%rsp) ++ vmovdqa 0x60(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm7,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm1,0x60(%rsp) ++ vperm2i128 $0x20,%ymm12,%ymm8,%ymm0 ++ vperm2i128 $0x31,%ymm12,%ymm8,%ymm12 ++ vmovdqa %ymm0,%ymm8 ++ vperm2i128 $0x20,%ymm13,%ymm9,%ymm0 ++ vperm2i128 $0x31,%ymm13,%ymm9,%ymm13 ++ vmovdqa %ymm0,%ymm9 ++ vperm2i128 $0x20,%ymm14,%ymm10,%ymm0 ++ vperm2i128 $0x31,%ymm14,%ymm10,%ymm14 ++ vmovdqa %ymm0,%ymm10 ++ vperm2i128 $0x20,%ymm15,%ymm11,%ymm0 ++ vperm2i128 $0x31,%ymm15,%ymm11,%ymm15 ++ vmovdqa %ymm0,%ymm11 ++ ++ # xor with corresponding input, write to output ++ vmovdqa 0x00(%rsp),%ymm0 ++ vpxor 0x0000(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0000(%rsi) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vpxor 0x0080(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0080(%rsi) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vpxor 0x0040(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0040(%rsi) ++ vmovdqa 0x60(%rsp),%ymm0 ++ vpxor 0x00c0(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x00c0(%rsi) ++ vpxor 0x0100(%rdx),%ymm4,%ymm4 ++ vmovdqu %ymm4,0x0100(%rsi) ++ vpxor 0x0180(%rdx),%ymm5,%ymm5 ++ vmovdqu %ymm5,0x00180(%rsi) ++ vpxor 0x0140(%rdx),%ymm6,%ymm6 ++ vmovdqu %ymm6,0x0140(%rsi) ++ vpxor 0x01c0(%rdx),%ymm7,%ymm7 ++ vmovdqu %ymm7,0x01c0(%rsi) ++ vpxor 0x0020(%rdx),%ymm8,%ymm8 ++ vmovdqu %ymm8,0x0020(%rsi) ++ vpxor 0x00a0(%rdx),%ymm9,%ymm9 ++ vmovdqu %ymm9,0x00a0(%rsi) ++ vpxor 0x0060(%rdx),%ymm10,%ymm10 ++ vmovdqu %ymm10,0x0060(%rsi) ++ vpxor 0x00e0(%rdx),%ymm11,%ymm11 ++ vmovdqu %ymm11,0x00e0(%rsi) ++ vpxor 0x0120(%rdx),%ymm12,%ymm12 ++ vmovdqu %ymm12,0x0120(%rsi) ++ vpxor 0x01a0(%rdx),%ymm13,%ymm13 ++ vmovdqu %ymm13,0x01a0(%rsi) ++ vpxor 0x0160(%rdx),%ymm14,%ymm14 ++ vmovdqu %ymm14,0x0160(%rsi) ++ vpxor 0x01e0(%rdx),%ymm15,%ymm15 ++ vmovdqu %ymm15,0x01e0(%rsi) ++ ++ vzeroupper ++ mov %r8,%rsp ++ ret ++ENDPROC(chacha20_asm_8block_xor_avx2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20-ssse3-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,627 @@ ++/* ++ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSSE3 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 16 ++ ++ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003 ++ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302 ++CTRINC: .octa 0x00000003000000020000000100000000 ++ ++.text ++ ++ENTRY(chacha20_asm_block_xor_ssse3) ++ # %rdi: Input state matrix, s ++ # %rsi: 1 data block output, o ++ # %rdx: 1 data block input, i ++ ++ # This function encrypts one ChaCha20 block by loading the state matrix ++ # in four SSE registers. It performs matrix operation on four words in ++ # parallel, but requireds shuffling to rearrange the words after each ++ # round. 8/16-bit word rotation is done with the slightly better ++ # performing SSSE3 byte shuffling, 7/12-bit word rotation uses ++ # traditional shift+OR. ++ ++ # x0..3 = s0..3 ++ movdqa 0x00(%rdi),%xmm0 ++ movdqa 0x10(%rdi),%xmm1 ++ movdqa 0x20(%rdi),%xmm2 ++ movdqa 0x30(%rdi),%xmm3 ++ movdqa %xmm0,%xmm8 ++ movdqa %xmm1,%xmm9 ++ movdqa %xmm2,%xmm10 ++ movdqa %xmm3,%xmm11 ++ ++ movdqa ROT8(%rip),%xmm4 ++ movdqa ROT16(%rip),%xmm5 ++ ++ mov $10,%ecx ++ ++.Ldoubleround: ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 16) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm5,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 12) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm6 ++ pslld $12,%xmm6 ++ psrld $20,%xmm1 ++ por %xmm6,%xmm1 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 8) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm4,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 7) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm7 ++ pslld $7,%xmm7 ++ psrld $25,%xmm1 ++ por %xmm7,%xmm1 ++ ++ # x1 = shuffle32(x1, MASK(0, 3, 2, 1)) ++ pshufd $0x39,%xmm1,%xmm1 ++ # x2 = shuffle32(x2, MASK(1, 0, 3, 2)) ++ pshufd $0x4e,%xmm2,%xmm2 ++ # x3 = shuffle32(x3, MASK(2, 1, 0, 3)) ++ pshufd $0x93,%xmm3,%xmm3 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 16) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm5,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 12) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm6 ++ pslld $12,%xmm6 ++ psrld $20,%xmm1 ++ por %xmm6,%xmm1 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 8) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm4,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 7) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm7 ++ pslld $7,%xmm7 ++ psrld $25,%xmm1 ++ por %xmm7,%xmm1 ++ ++ # x1 = shuffle32(x1, MASK(2, 1, 0, 3)) ++ pshufd $0x93,%xmm1,%xmm1 ++ # x2 = shuffle32(x2, MASK(1, 0, 3, 2)) ++ pshufd $0x4e,%xmm2,%xmm2 ++ # x3 = shuffle32(x3, MASK(0, 3, 2, 1)) ++ pshufd $0x39,%xmm3,%xmm3 ++ ++ dec %ecx ++ jnz .Ldoubleround ++ ++ # o0 = i0 ^ (x0 + s0) ++ movdqu 0x00(%rdx),%xmm4 ++ paddd %xmm8,%xmm0 ++ pxor %xmm4,%xmm0 ++ movdqu %xmm0,0x00(%rsi) ++ # o1 = i1 ^ (x1 + s1) ++ movdqu 0x10(%rdx),%xmm5 ++ paddd %xmm9,%xmm1 ++ pxor %xmm5,%xmm1 ++ movdqu %xmm1,0x10(%rsi) ++ # o2 = i2 ^ (x2 + s2) ++ movdqu 0x20(%rdx),%xmm6 ++ paddd %xmm10,%xmm2 ++ pxor %xmm6,%xmm2 ++ movdqu %xmm2,0x20(%rsi) ++ # o3 = i3 ^ (x3 + s3) ++ movdqu 0x30(%rdx),%xmm7 ++ paddd %xmm11,%xmm3 ++ pxor %xmm7,%xmm3 ++ movdqu %xmm3,0x30(%rsi) ++ ++ ret ++ENDPROC(chacha20_asm_block_xor_ssse3) ++ ++ENTRY(chacha20_asm_4block_xor_ssse3) ++ # %rdi: Input state matrix, s ++ # %rsi: 4 data blocks output, o ++ # %rdx: 4 data blocks input, i ++ ++ # This function encrypts four consecutive ChaCha20 blocks by loading the ++ # the state matrix in SSE registers four times. As we need some scratch ++ # registers, we save the first four registers on the stack. The ++ # algorithm performs each operation on the corresponding word of each ++ # state matrix, hence requires no word shuffling. For final XORing step ++ # we transpose the matrix by interleaving 32- and then 64-bit words, ++ # which allows us to do XOR in SSE registers. 8/16-bit word rotation is ++ # done with the slightly better performing SSSE3 byte shuffling, ++ # 7/12-bit word rotation uses traditional shift+OR. ++ ++ mov %rsp,%r11 ++ sub $0x80,%rsp ++ and $~63,%rsp ++ ++ # x0..15[0-3] = s0..3[0..3] ++ movq 0x00(%rdi),%xmm1 ++ pshufd $0x00,%xmm1,%xmm0 ++ pshufd $0x55,%xmm1,%xmm1 ++ movq 0x08(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ movq 0x10(%rdi),%xmm5 ++ pshufd $0x00,%xmm5,%xmm4 ++ pshufd $0x55,%xmm5,%xmm5 ++ movq 0x18(%rdi),%xmm7 ++ pshufd $0x00,%xmm7,%xmm6 ++ pshufd $0x55,%xmm7,%xmm7 ++ movq 0x20(%rdi),%xmm9 ++ pshufd $0x00,%xmm9,%xmm8 ++ pshufd $0x55,%xmm9,%xmm9 ++ movq 0x28(%rdi),%xmm11 ++ pshufd $0x00,%xmm11,%xmm10 ++ pshufd $0x55,%xmm11,%xmm11 ++ movq 0x30(%rdi),%xmm13 ++ pshufd $0x00,%xmm13,%xmm12 ++ pshufd $0x55,%xmm13,%xmm13 ++ movq 0x38(%rdi),%xmm15 ++ pshufd $0x00,%xmm15,%xmm14 ++ pshufd $0x55,%xmm15,%xmm15 ++ # x0..3 on stack ++ movdqa %xmm0,0x00(%rsp) ++ movdqa %xmm1,0x10(%rsp) ++ movdqa %xmm2,0x20(%rsp) ++ movdqa %xmm3,0x30(%rsp) ++ ++ movdqa CTRINC(%rip),%xmm1 ++ movdqa ROT8(%rip),%xmm2 ++ movdqa ROT16(%rip),%xmm3 ++ ++ # x12 += counter values 0-3 ++ paddd %xmm1,%xmm12 ++ ++ mov $10,%ecx ++ ++.Ldoubleround4: ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 16) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm3,%xmm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 16) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm3,%xmm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 16) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm3,%xmm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 16) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm3,%xmm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 12) ++ paddd %xmm12,%xmm8 ++ pxor %xmm8,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm4 ++ por %xmm0,%xmm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 12) ++ paddd %xmm13,%xmm9 ++ pxor %xmm9,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm5 ++ por %xmm0,%xmm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 12) ++ paddd %xmm14,%xmm10 ++ pxor %xmm10,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm6 ++ por %xmm0,%xmm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 12) ++ paddd %xmm15,%xmm11 ++ pxor %xmm11,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm7 ++ por %xmm0,%xmm7 ++ ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 8) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm2,%xmm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 8) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm2,%xmm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 8) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm2,%xmm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 8) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm2,%xmm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 7) ++ paddd %xmm12,%xmm8 ++ pxor %xmm8,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm4 ++ por %xmm0,%xmm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 7) ++ paddd %xmm13,%xmm9 ++ pxor %xmm9,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm5 ++ por %xmm0,%xmm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 7) ++ paddd %xmm14,%xmm10 ++ pxor %xmm10,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm6 ++ por %xmm0,%xmm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 7) ++ paddd %xmm15,%xmm11 ++ pxor %xmm11,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm7 ++ por %xmm0,%xmm7 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 16) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm3,%xmm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 16) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm3,%xmm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 16) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm3,%xmm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 16) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm3,%xmm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 12) ++ paddd %xmm15,%xmm10 ++ pxor %xmm10,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm5 ++ por %xmm0,%xmm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 12) ++ paddd %xmm12,%xmm11 ++ pxor %xmm11,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm6 ++ por %xmm0,%xmm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 12) ++ paddd %xmm13,%xmm8 ++ pxor %xmm8,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm7 ++ por %xmm0,%xmm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 12) ++ paddd %xmm14,%xmm9 ++ pxor %xmm9,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm4 ++ por %xmm0,%xmm4 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 8) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm2,%xmm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 8) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm2,%xmm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 8) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm2,%xmm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 8) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm2,%xmm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 7) ++ paddd %xmm15,%xmm10 ++ pxor %xmm10,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm5 ++ por %xmm0,%xmm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 7) ++ paddd %xmm12,%xmm11 ++ pxor %xmm11,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm6 ++ por %xmm0,%xmm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 7) ++ paddd %xmm13,%xmm8 ++ pxor %xmm8,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm7 ++ por %xmm0,%xmm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 7) ++ paddd %xmm14,%xmm9 ++ pxor %xmm9,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm4 ++ por %xmm0,%xmm4 ++ ++ dec %ecx ++ jnz .Ldoubleround4 ++ ++ # x0[0-3] += s0[0] ++ # x1[0-3] += s0[1] ++ movq 0x00(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd 0x00(%rsp),%xmm2 ++ movdqa %xmm2,0x00(%rsp) ++ paddd 0x10(%rsp),%xmm3 ++ movdqa %xmm3,0x10(%rsp) ++ # x2[0-3] += s0[2] ++ # x3[0-3] += s0[3] ++ movq 0x08(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd 0x20(%rsp),%xmm2 ++ movdqa %xmm2,0x20(%rsp) ++ paddd 0x30(%rsp),%xmm3 ++ movdqa %xmm3,0x30(%rsp) ++ ++ # x4[0-3] += s1[0] ++ # x5[0-3] += s1[1] ++ movq 0x10(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm4 ++ paddd %xmm3,%xmm5 ++ # x6[0-3] += s1[2] ++ # x7[0-3] += s1[3] ++ movq 0x18(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm6 ++ paddd %xmm3,%xmm7 ++ ++ # x8[0-3] += s2[0] ++ # x9[0-3] += s2[1] ++ movq 0x20(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm8 ++ paddd %xmm3,%xmm9 ++ # x10[0-3] += s2[2] ++ # x11[0-3] += s2[3] ++ movq 0x28(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm10 ++ paddd %xmm3,%xmm11 ++ ++ # x12[0-3] += s3[0] ++ # x13[0-3] += s3[1] ++ movq 0x30(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm12 ++ paddd %xmm3,%xmm13 ++ # x14[0-3] += s3[2] ++ # x15[0-3] += s3[3] ++ movq 0x38(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm14 ++ paddd %xmm3,%xmm15 ++ ++ # x12 += counter values 0-3 ++ paddd %xmm1,%xmm12 ++ ++ # interleave 32-bit words in state n, n+1 ++ movdqa 0x00(%rsp),%xmm0 ++ movdqa 0x10(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpckldq %xmm1,%xmm2 ++ punpckhdq %xmm1,%xmm0 ++ movdqa %xmm2,0x00(%rsp) ++ movdqa %xmm0,0x10(%rsp) ++ movdqa 0x20(%rsp),%xmm0 ++ movdqa 0x30(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpckldq %xmm1,%xmm2 ++ punpckhdq %xmm1,%xmm0 ++ movdqa %xmm2,0x20(%rsp) ++ movdqa %xmm0,0x30(%rsp) ++ movdqa %xmm4,%xmm0 ++ punpckldq %xmm5,%xmm4 ++ punpckhdq %xmm5,%xmm0 ++ movdqa %xmm0,%xmm5 ++ movdqa %xmm6,%xmm0 ++ punpckldq %xmm7,%xmm6 ++ punpckhdq %xmm7,%xmm0 ++ movdqa %xmm0,%xmm7 ++ movdqa %xmm8,%xmm0 ++ punpckldq %xmm9,%xmm8 ++ punpckhdq %xmm9,%xmm0 ++ movdqa %xmm0,%xmm9 ++ movdqa %xmm10,%xmm0 ++ punpckldq %xmm11,%xmm10 ++ punpckhdq %xmm11,%xmm0 ++ movdqa %xmm0,%xmm11 ++ movdqa %xmm12,%xmm0 ++ punpckldq %xmm13,%xmm12 ++ punpckhdq %xmm13,%xmm0 ++ movdqa %xmm0,%xmm13 ++ movdqa %xmm14,%xmm0 ++ punpckldq %xmm15,%xmm14 ++ punpckhdq %xmm15,%xmm0 ++ movdqa %xmm0,%xmm15 ++ ++ # interleave 64-bit words in state n, n+2 ++ movdqa 0x00(%rsp),%xmm0 ++ movdqa 0x20(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpcklqdq %xmm1,%xmm2 ++ punpckhqdq %xmm1,%xmm0 ++ movdqa %xmm2,0x00(%rsp) ++ movdqa %xmm0,0x20(%rsp) ++ movdqa 0x10(%rsp),%xmm0 ++ movdqa 0x30(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpcklqdq %xmm1,%xmm2 ++ punpckhqdq %xmm1,%xmm0 ++ movdqa %xmm2,0x10(%rsp) ++ movdqa %xmm0,0x30(%rsp) ++ movdqa %xmm4,%xmm0 ++ punpcklqdq %xmm6,%xmm4 ++ punpckhqdq %xmm6,%xmm0 ++ movdqa %xmm0,%xmm6 ++ movdqa %xmm5,%xmm0 ++ punpcklqdq %xmm7,%xmm5 ++ punpckhqdq %xmm7,%xmm0 ++ movdqa %xmm0,%xmm7 ++ movdqa %xmm8,%xmm0 ++ punpcklqdq %xmm10,%xmm8 ++ punpckhqdq %xmm10,%xmm0 ++ movdqa %xmm0,%xmm10 ++ movdqa %xmm9,%xmm0 ++ punpcklqdq %xmm11,%xmm9 ++ punpckhqdq %xmm11,%xmm0 ++ movdqa %xmm0,%xmm11 ++ movdqa %xmm12,%xmm0 ++ punpcklqdq %xmm14,%xmm12 ++ punpckhqdq %xmm14,%xmm0 ++ movdqa %xmm0,%xmm14 ++ movdqa %xmm13,%xmm0 ++ punpcklqdq %xmm15,%xmm13 ++ punpckhqdq %xmm15,%xmm0 ++ movdqa %xmm0,%xmm15 ++ ++ # xor with corresponding input, write to output ++ movdqa 0x00(%rsp),%xmm0 ++ movdqu 0x00(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x00(%rsi) ++ movdqa 0x10(%rsp),%xmm0 ++ movdqu 0x80(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x80(%rsi) ++ movdqa 0x20(%rsp),%xmm0 ++ movdqu 0x40(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x40(%rsi) ++ movdqa 0x30(%rsp),%xmm0 ++ movdqu 0xc0(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0xc0(%rsi) ++ movdqu 0x10(%rdx),%xmm1 ++ pxor %xmm1,%xmm4 ++ movdqu %xmm4,0x10(%rsi) ++ movdqu 0x90(%rdx),%xmm1 ++ pxor %xmm1,%xmm5 ++ movdqu %xmm5,0x90(%rsi) ++ movdqu 0x50(%rdx),%xmm1 ++ pxor %xmm1,%xmm6 ++ movdqu %xmm6,0x50(%rsi) ++ movdqu 0xd0(%rdx),%xmm1 ++ pxor %xmm1,%xmm7 ++ movdqu %xmm7,0xd0(%rsi) ++ movdqu 0x20(%rdx),%xmm1 ++ pxor %xmm1,%xmm8 ++ movdqu %xmm8,0x20(%rsi) ++ movdqu 0xa0(%rdx),%xmm1 ++ pxor %xmm1,%xmm9 ++ movdqu %xmm9,0xa0(%rsi) ++ movdqu 0x60(%rdx),%xmm1 ++ pxor %xmm1,%xmm10 ++ movdqu %xmm10,0x60(%rsi) ++ movdqu 0xe0(%rdx),%xmm1 ++ pxor %xmm1,%xmm11 ++ movdqu %xmm11,0xe0(%rsi) ++ movdqu 0x30(%rdx),%xmm1 ++ pxor %xmm1,%xmm12 ++ movdqu %xmm12,0x30(%rsi) ++ movdqu 0xb0(%rdx),%xmm1 ++ pxor %xmm1,%xmm13 ++ movdqu %xmm13,0xb0(%rsi) ++ movdqu 0x70(%rdx),%xmm1 ++ pxor %xmm1,%xmm14 ++ movdqu %xmm14,0x70(%rsi) ++ movdqu 0xf0(%rdx),%xmm1 ++ pxor %xmm1,%xmm15 ++ movdqu %xmm15,0xf0(%rsi) ++ ++ mov %r11,%rsp ++ ret ++ENDPROC(chacha20_asm_4block_xor_ssse3) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/poly1305-avx2-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,386 @@ ++/* ++ * Poly1305 authenticator algorithm, RFC7539, x64 AVX2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 32 ++ ++ANMASK: .octa 0x0000000003ffffff0000000003ffffff ++ .octa 0x0000000003ffffff0000000003ffffff ++ORMASK: .octa 0x00000000010000000000000001000000 ++ .octa 0x00000000010000000000000001000000 ++ ++.text ++ ++#define h0 0x00(%rdi) ++#define h1 0x04(%rdi) ++#define h2 0x08(%rdi) ++#define h3 0x0c(%rdi) ++#define h4 0x10(%rdi) ++#define r0 0x00(%rdx) ++#define r1 0x04(%rdx) ++#define r2 0x08(%rdx) ++#define r3 0x0c(%rdx) ++#define r4 0x10(%rdx) ++#define u0 0x00(%r8) ++#define u1 0x04(%r8) ++#define u2 0x08(%r8) ++#define u3 0x0c(%r8) ++#define u4 0x10(%r8) ++#define w0 0x14(%r8) ++#define w1 0x18(%r8) ++#define w2 0x1c(%r8) ++#define w3 0x20(%r8) ++#define w4 0x24(%r8) ++#define y0 0x28(%r8) ++#define y1 0x2c(%r8) ++#define y2 0x30(%r8) ++#define y3 0x34(%r8) ++#define y4 0x38(%r8) ++#define m %rsi ++#define hc0 %ymm0 ++#define hc1 %ymm1 ++#define hc2 %ymm2 ++#define hc3 %ymm3 ++#define hc4 %ymm4 ++#define hc0x %xmm0 ++#define hc1x %xmm1 ++#define hc2x %xmm2 ++#define hc3x %xmm3 ++#define hc4x %xmm4 ++#define t1 %ymm5 ++#define t2 %ymm6 ++#define t1x %xmm5 ++#define t2x %xmm6 ++#define ruwy0 %ymm7 ++#define ruwy1 %ymm8 ++#define ruwy2 %ymm9 ++#define ruwy3 %ymm10 ++#define ruwy4 %ymm11 ++#define ruwy0x %xmm7 ++#define ruwy1x %xmm8 ++#define ruwy2x %xmm9 ++#define ruwy3x %xmm10 ++#define ruwy4x %xmm11 ++#define svxz1 %ymm12 ++#define svxz2 %ymm13 ++#define svxz3 %ymm14 ++#define svxz4 %ymm15 ++#define d0 %r9 ++#define d1 %r10 ++#define d2 %r11 ++#define d3 %r12 ++#define d4 %r13 ++ ++ENTRY(poly1305_asm_4block_avx2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 64 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Quadblock count ++ # %r8: Poly1305 derived key r^2 u[5], r^3 w[5], r^4 y[5], ++ ++ # This four-block variant uses loop unrolled block processing. It ++ # requires 4 Poly1305 keys: r, r^2, r^3 and r^4: ++ # h = (h + m) * r => h = (h + m1) * r^4 + m2 * r^3 + m3 * r^2 + m4 * r ++ ++ vzeroupper ++ push %rbx ++ push %r12 ++ push %r13 ++ ++ # combine r0,u0,w0,y0 ++ vmovd y0,ruwy0x ++ vmovd w0,t1x ++ vpunpcklqdq t1,ruwy0,ruwy0 ++ vmovd u0,t1x ++ vmovd r0,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy0,ruwy0 ++ ++ # combine r1,u1,w1,y1 and s1=r1*5,v1=u1*5,x1=w1*5,z1=y1*5 ++ vmovd y1,ruwy1x ++ vmovd w1,t1x ++ vpunpcklqdq t1,ruwy1,ruwy1 ++ vmovd u1,t1x ++ vmovd r1,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy1,ruwy1 ++ vpslld $2,ruwy1,svxz1 ++ vpaddd ruwy1,svxz1,svxz1 ++ ++ # combine r2,u2,w2,y2 and s2=r2*5,v2=u2*5,x2=w2*5,z2=y2*5 ++ vmovd y2,ruwy2x ++ vmovd w2,t1x ++ vpunpcklqdq t1,ruwy2,ruwy2 ++ vmovd u2,t1x ++ vmovd r2,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy2,ruwy2 ++ vpslld $2,ruwy2,svxz2 ++ vpaddd ruwy2,svxz2,svxz2 ++ ++ # combine r3,u3,w3,y3 and s3=r3*5,v3=u3*5,x3=w3*5,z3=y3*5 ++ vmovd y3,ruwy3x ++ vmovd w3,t1x ++ vpunpcklqdq t1,ruwy3,ruwy3 ++ vmovd u3,t1x ++ vmovd r3,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy3,ruwy3 ++ vpslld $2,ruwy3,svxz3 ++ vpaddd ruwy3,svxz3,svxz3 ++ ++ # combine r4,u4,w4,y4 and s4=r4*5,v4=u4*5,x4=w4*5,z4=y4*5 ++ vmovd y4,ruwy4x ++ vmovd w4,t1x ++ vpunpcklqdq t1,ruwy4,ruwy4 ++ vmovd u4,t1x ++ vmovd r4,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy4,ruwy4 ++ vpslld $2,ruwy4,svxz4 ++ vpaddd ruwy4,svxz4,svxz4 ++ ++.Ldoblock4: ++ # hc0 = [m[48-51] & 0x3ffffff, m[32-35] & 0x3ffffff, ++ # m[16-19] & 0x3ffffff, m[ 0- 3] & 0x3ffffff + h0] ++ vmovd 0x00(m),hc0x ++ vmovd 0x10(m),t1x ++ vpunpcklqdq t1,hc0,hc0 ++ vmovd 0x20(m),t1x ++ vmovd 0x30(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc0,hc0 ++ vpand ANMASK(%rip),hc0,hc0 ++ vmovd h0,t1x ++ vpaddd t1,hc0,hc0 ++ # hc1 = [(m[51-54] >> 2) & 0x3ffffff, (m[35-38] >> 2) & 0x3ffffff, ++ # (m[19-22] >> 2) & 0x3ffffff, (m[ 3- 6] >> 2) & 0x3ffffff + h1] ++ vmovd 0x03(m),hc1x ++ vmovd 0x13(m),t1x ++ vpunpcklqdq t1,hc1,hc1 ++ vmovd 0x23(m),t1x ++ vmovd 0x33(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc1,hc1 ++ vpsrld $2,hc1,hc1 ++ vpand ANMASK(%rip),hc1,hc1 ++ vmovd h1,t1x ++ vpaddd t1,hc1,hc1 ++ # hc2 = [(m[54-57] >> 4) & 0x3ffffff, (m[38-41] >> 4) & 0x3ffffff, ++ # (m[22-25] >> 4) & 0x3ffffff, (m[ 6- 9] >> 4) & 0x3ffffff + h2] ++ vmovd 0x06(m),hc2x ++ vmovd 0x16(m),t1x ++ vpunpcklqdq t1,hc2,hc2 ++ vmovd 0x26(m),t1x ++ vmovd 0x36(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc2,hc2 ++ vpsrld $4,hc2,hc2 ++ vpand ANMASK(%rip),hc2,hc2 ++ vmovd h2,t1x ++ vpaddd t1,hc2,hc2 ++ # hc3 = [(m[57-60] >> 6) & 0x3ffffff, (m[41-44] >> 6) & 0x3ffffff, ++ # (m[25-28] >> 6) & 0x3ffffff, (m[ 9-12] >> 6) & 0x3ffffff + h3] ++ vmovd 0x09(m),hc3x ++ vmovd 0x19(m),t1x ++ vpunpcklqdq t1,hc3,hc3 ++ vmovd 0x29(m),t1x ++ vmovd 0x39(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc3,hc3 ++ vpsrld $6,hc3,hc3 ++ vpand ANMASK(%rip),hc3,hc3 ++ vmovd h3,t1x ++ vpaddd t1,hc3,hc3 ++ # hc4 = [(m[60-63] >> 8) | (1<<24), (m[44-47] >> 8) | (1<<24), ++ # (m[28-31] >> 8) | (1<<24), (m[12-15] >> 8) | (1<<24) + h4] ++ vmovd 0x0c(m),hc4x ++ vmovd 0x1c(m),t1x ++ vpunpcklqdq t1,hc4,hc4 ++ vmovd 0x2c(m),t1x ++ vmovd 0x3c(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc4,hc4 ++ vpsrld $8,hc4,hc4 ++ vpor ORMASK(%rip),hc4,hc4 ++ vmovd h4,t1x ++ vpaddd t1,hc4,hc4 ++ ++ # t1 = [ hc0[3] * r0, hc0[2] * u0, hc0[1] * w0, hc0[0] * y0 ] ++ vpmuludq hc0,ruwy0,t1 ++ # t1 += [ hc1[3] * s4, hc1[2] * v4, hc1[1] * x4, hc1[0] * z4 ] ++ vpmuludq hc1,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * s3, hc2[2] * v3, hc2[1] * x3, hc2[0] * z3 ] ++ vpmuludq hc2,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s2, hc3[2] * v2, hc3[1] * x2, hc3[0] * z2 ] ++ vpmuludq hc3,svxz2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s1, hc4[2] * v1, hc4[1] * x1, hc4[0] * z1 ] ++ vpmuludq hc4,svxz1,t2 ++ vpaddq t2,t1,t1 ++ # d0 = t1[0] + t1[1] + t[2] + t[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d0 ++ ++ # t1 = [ hc0[3] * r1, hc0[2] * u1,hc0[1] * w1, hc0[0] * y1 ] ++ vpmuludq hc0,ruwy1,t1 ++ # t1 += [ hc1[3] * r0, hc1[2] * u0, hc1[1] * w0, hc1[0] * y0 ] ++ vpmuludq hc1,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * s4, hc2[2] * v4, hc2[1] * x4, hc2[0] * z4 ] ++ vpmuludq hc2,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s3, hc3[2] * v3, hc3[1] * x3, hc3[0] * z3 ] ++ vpmuludq hc3,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s2, hc4[2] * v2, hc4[1] * x2, hc4[0] * z2 ] ++ vpmuludq hc4,svxz2,t2 ++ vpaddq t2,t1,t1 ++ # d1 = t1[0] + t1[1] + t1[3] + t1[4] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d1 ++ ++ # t1 = [ hc0[3] * r2, hc0[2] * u2, hc0[1] * w2, hc0[0] * y2 ] ++ vpmuludq hc0,ruwy2,t1 ++ # t1 += [ hc1[3] * r1, hc1[2] * u1, hc1[1] * w1, hc1[0] * y1 ] ++ vpmuludq hc1,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r0, hc2[2] * u0, hc2[1] * w0, hc2[0] * y0 ] ++ vpmuludq hc2,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s4, hc3[2] * v4, hc3[1] * x4, hc3[0] * z4 ] ++ vpmuludq hc3,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s3, hc4[2] * v3, hc4[1] * x3, hc4[0] * z3 ] ++ vpmuludq hc4,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # d2 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d2 ++ ++ # t1 = [ hc0[3] * r3, hc0[2] * u3, hc0[1] * w3, hc0[0] * y3 ] ++ vpmuludq hc0,ruwy3,t1 ++ # t1 += [ hc1[3] * r2, hc1[2] * u2, hc1[1] * w2, hc1[0] * y2 ] ++ vpmuludq hc1,ruwy2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r1, hc2[2] * u1, hc2[1] * w1, hc2[0] * y1 ] ++ vpmuludq hc2,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * r0, hc3[2] * u0, hc3[1] * w0, hc3[0] * y0 ] ++ vpmuludq hc3,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s4, hc4[2] * v4, hc4[1] * x4, hc4[0] * z4 ] ++ vpmuludq hc4,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # d3 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d3 ++ ++ # t1 = [ hc0[3] * r4, hc0[2] * u4, hc0[1] * w4, hc0[0] * y4 ] ++ vpmuludq hc0,ruwy4,t1 ++ # t1 += [ hc1[3] * r3, hc1[2] * u3, hc1[1] * w3, hc1[0] * y3 ] ++ vpmuludq hc1,ruwy3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r2, hc2[2] * u2, hc2[1] * w2, hc2[0] * y2 ] ++ vpmuludq hc2,ruwy2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * r1, hc3[2] * u1, hc3[1] * w1, hc3[0] * y1 ] ++ vpmuludq hc3,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * r0, hc4[2] * u0, hc4[1] * w0, hc4[0] * y0 ] ++ vpmuludq hc4,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # d4 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x40,m ++ dec %rcx ++ jnz .Ldoblock4 ++ ++ vzeroupper ++ pop %r13 ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_4block_avx2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/poly1305-sse2-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,582 @@ ++/* ++ * Poly1305 authenticator algorithm, RFC7539, x64 SSE2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 16 ++ ++ANMASK: .octa 0x0000000003ffffff0000000003ffffff ++ORMASK: .octa 0x00000000010000000000000001000000 ++ ++.text ++ ++#define h0 0x00(%rdi) ++#define h1 0x04(%rdi) ++#define h2 0x08(%rdi) ++#define h3 0x0c(%rdi) ++#define h4 0x10(%rdi) ++#define r0 0x00(%rdx) ++#define r1 0x04(%rdx) ++#define r2 0x08(%rdx) ++#define r3 0x0c(%rdx) ++#define r4 0x10(%rdx) ++#define s1 0x00(%rsp) ++#define s2 0x04(%rsp) ++#define s3 0x08(%rsp) ++#define s4 0x0c(%rsp) ++#define m %rsi ++#define h01 %xmm0 ++#define h23 %xmm1 ++#define h44 %xmm2 ++#define t1 %xmm3 ++#define t2 %xmm4 ++#define t3 %xmm5 ++#define t4 %xmm6 ++#define mask %xmm7 ++#define d0 %r8 ++#define d1 %r9 ++#define d2 %r10 ++#define d3 %r11 ++#define d4 %r12 ++ ++ENTRY(poly1305_asm_block_sse2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 16 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Block count ++ ++ # This single block variant tries to improve performance by doing two ++ # multiplications in parallel using SSE instructions. There is quite ++ # some quardword packing involved, hence the speedup is marginal. ++ ++ push %rbx ++ push %r12 ++ sub $0x10,%rsp ++ ++ # s1..s4 = r1..r4 * 5 ++ mov r1,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s1 ++ mov r2,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s2 ++ mov r3,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s3 ++ mov r4,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s4 ++ ++ movdqa ANMASK(%rip),mask ++ ++.Ldoblock: ++ # h01 = [0, h1, 0, h0] ++ # h23 = [0, h3, 0, h2] ++ # h44 = [0, h4, 0, h4] ++ movd h0,h01 ++ movd h1,t1 ++ movd h2,h23 ++ movd h3,t2 ++ movd h4,h44 ++ punpcklqdq t1,h01 ++ punpcklqdq t2,h23 ++ punpcklqdq h44,h44 ++ ++ # h01 += [ (m[3-6] >> 2) & 0x3ffffff, m[0-3] & 0x3ffffff ] ++ movd 0x00(m),t1 ++ movd 0x03(m),t2 ++ psrld $2,t2 ++ punpcklqdq t2,t1 ++ pand mask,t1 ++ paddd t1,h01 ++ # h23 += [ (m[9-12] >> 6) & 0x3ffffff, (m[6-9] >> 4) & 0x3ffffff ] ++ movd 0x06(m),t1 ++ movd 0x09(m),t2 ++ psrld $4,t1 ++ psrld $6,t2 ++ punpcklqdq t2,t1 ++ pand mask,t1 ++ paddd t1,h23 ++ # h44 += [ (m[12-15] >> 8) | (1 << 24), (m[12-15] >> 8) | (1 << 24) ] ++ mov 0x0c(m),%eax ++ shr $8,%eax ++ or $0x01000000,%eax ++ movd %eax,t1 ++ pshufd $0xc4,t1,t1 ++ paddd t1,h44 ++ ++ # t1[0] = h0 * r0 + h2 * s3 ++ # t1[1] = h1 * s4 + h3 * s2 ++ movd r0,t1 ++ movd s4,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd s3,t2 ++ movd s2,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t2[0] = h0 * r1 + h2 * s4 ++ # t2[1] = h1 * r0 + h3 * s3 ++ movd r1,t2 ++ movd r0,t3 ++ punpcklqdq t3,t2 ++ pmuludq h01,t2 ++ movd s4,t3 ++ movd s3,t4 ++ punpcklqdq t4,t3 ++ pmuludq h23,t3 ++ paddq t3,t2 ++ # t3[0] = h4 * s1 ++ # t3[1] = h4 * s2 ++ movd s1,t3 ++ movd s2,t4 ++ punpcklqdq t4,t3 ++ pmuludq h44,t3 ++ # d0 = t1[0] + t1[1] + t3[0] ++ # d1 = t2[0] + t2[1] + t3[1] ++ movdqa t1,t4 ++ punpcklqdq t2,t4 ++ punpckhqdq t2,t1 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d0 ++ psrldq $8,t1 ++ movq t1,d1 ++ ++ # t1[0] = h0 * r2 + h2 * r0 ++ # t1[1] = h1 * r1 + h3 * s4 ++ movd r2,t1 ++ movd r1,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd r0,t2 ++ movd s4,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t2[0] = h0 * r3 + h2 * r1 ++ # t2[1] = h1 * r2 + h3 * r0 ++ movd r3,t2 ++ movd r2,t3 ++ punpcklqdq t3,t2 ++ pmuludq h01,t2 ++ movd r1,t3 ++ movd r0,t4 ++ punpcklqdq t4,t3 ++ pmuludq h23,t3 ++ paddq t3,t2 ++ # t3[0] = h4 * s3 ++ # t3[1] = h4 * s4 ++ movd s3,t3 ++ movd s4,t4 ++ punpcklqdq t4,t3 ++ pmuludq h44,t3 ++ # d2 = t1[0] + t1[1] + t3[0] ++ # d3 = t2[0] + t2[1] + t3[1] ++ movdqa t1,t4 ++ punpcklqdq t2,t4 ++ punpckhqdq t2,t1 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d2 ++ psrldq $8,t1 ++ movq t1,d3 ++ ++ # t1[0] = h0 * r4 + h2 * r2 ++ # t1[1] = h1 * r3 + h3 * r1 ++ movd r4,t1 ++ movd r3,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd r2,t2 ++ movd r1,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t3[0] = h4 * r0 ++ movd r0,t3 ++ pmuludq h44,t3 ++ # d4 = t1[0] + t1[1] + t3[0] ++ movdqa t1,t4 ++ psrldq $8,t4 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x10,m ++ dec %rcx ++ jnz .Ldoblock ++ ++ add $0x10,%rsp ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_block_sse2) ++ ++ ++#define u0 0x00(%r8) ++#define u1 0x04(%r8) ++#define u2 0x08(%r8) ++#define u3 0x0c(%r8) ++#define u4 0x10(%r8) ++#define hc0 %xmm0 ++#define hc1 %xmm1 ++#define hc2 %xmm2 ++#define hc3 %xmm5 ++#define hc4 %xmm6 ++#define ru0 %xmm7 ++#define ru1 %xmm8 ++#define ru2 %xmm9 ++#define ru3 %xmm10 ++#define ru4 %xmm11 ++#define sv1 %xmm12 ++#define sv2 %xmm13 ++#define sv3 %xmm14 ++#define sv4 %xmm15 ++#undef d0 ++#define d0 %r13 ++ ++ENTRY(poly1305_asm_2block_sse2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 16 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Doubleblock count ++ # %r8: Poly1305 derived key r^2 u[5] ++ ++ # This two-block variant further improves performance by using loop ++ # unrolled block processing. This is more straight forward and does ++ # less byte shuffling, but requires a second Poly1305 key r^2: ++ # h = (h + m) * r => h = (h + m1) * r^2 + m2 * r ++ ++ push %rbx ++ push %r12 ++ push %r13 ++ ++ # combine r0,u0 ++ movd u0,ru0 ++ movd r0,t1 ++ punpcklqdq t1,ru0 ++ ++ # combine r1,u1 and s1=r1*5,v1=u1*5 ++ movd u1,ru1 ++ movd r1,t1 ++ punpcklqdq t1,ru1 ++ movdqa ru1,sv1 ++ pslld $2,sv1 ++ paddd ru1,sv1 ++ ++ # combine r2,u2 and s2=r2*5,v2=u2*5 ++ movd u2,ru2 ++ movd r2,t1 ++ punpcklqdq t1,ru2 ++ movdqa ru2,sv2 ++ pslld $2,sv2 ++ paddd ru2,sv2 ++ ++ # combine r3,u3 and s3=r3*5,v3=u3*5 ++ movd u3,ru3 ++ movd r3,t1 ++ punpcklqdq t1,ru3 ++ movdqa ru3,sv3 ++ pslld $2,sv3 ++ paddd ru3,sv3 ++ ++ # combine r4,u4 and s4=r4*5,v4=u4*5 ++ movd u4,ru4 ++ movd r4,t1 ++ punpcklqdq t1,ru4 ++ movdqa ru4,sv4 ++ pslld $2,sv4 ++ paddd ru4,sv4 ++ ++.Ldoblock2: ++ # hc0 = [ m[16-19] & 0x3ffffff, h0 + m[0-3] & 0x3ffffff ] ++ movd 0x00(m),hc0 ++ movd 0x10(m),t1 ++ punpcklqdq t1,hc0 ++ pand ANMASK(%rip),hc0 ++ movd h0,t1 ++ paddd t1,hc0 ++ # hc1 = [ (m[19-22] >> 2) & 0x3ffffff, h1 + (m[3-6] >> 2) & 0x3ffffff ] ++ movd 0x03(m),hc1 ++ movd 0x13(m),t1 ++ punpcklqdq t1,hc1 ++ psrld $2,hc1 ++ pand ANMASK(%rip),hc1 ++ movd h1,t1 ++ paddd t1,hc1 ++ # hc2 = [ (m[22-25] >> 4) & 0x3ffffff, h2 + (m[6-9] >> 4) & 0x3ffffff ] ++ movd 0x06(m),hc2 ++ movd 0x16(m),t1 ++ punpcklqdq t1,hc2 ++ psrld $4,hc2 ++ pand ANMASK(%rip),hc2 ++ movd h2,t1 ++ paddd t1,hc2 ++ # hc3 = [ (m[25-28] >> 6) & 0x3ffffff, h3 + (m[9-12] >> 6) & 0x3ffffff ] ++ movd 0x09(m),hc3 ++ movd 0x19(m),t1 ++ punpcklqdq t1,hc3 ++ psrld $6,hc3 ++ pand ANMASK(%rip),hc3 ++ movd h3,t1 ++ paddd t1,hc3 ++ # hc4 = [ (m[28-31] >> 8) | (1<<24), h4 + (m[12-15] >> 8) | (1<<24) ] ++ movd 0x0c(m),hc4 ++ movd 0x1c(m),t1 ++ punpcklqdq t1,hc4 ++ psrld $8,hc4 ++ por ORMASK(%rip),hc4 ++ movd h4,t1 ++ paddd t1,hc4 ++ ++ # t1 = [ hc0[1] * r0, hc0[0] * u0 ] ++ movdqa ru0,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * s4, hc1[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * s3, hc2[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s2, hc3[0] * v2 ] ++ movdqa sv2,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s1, hc4[0] * v1 ] ++ movdqa sv1,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d0 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d0 ++ ++ # t1 = [ hc0[1] * r1, hc0[0] * u1 ] ++ movdqa ru1,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r0, hc1[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * s4, hc2[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s3, hc3[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s2, hc4[0] * v2 ] ++ movdqa sv2,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d1 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d1 ++ ++ # t1 = [ hc0[1] * r2, hc0[0] * u2 ] ++ movdqa ru2,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r1, hc1[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r0, hc2[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s4, hc3[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s3, hc4[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d2 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d2 ++ ++ # t1 = [ hc0[1] * r3, hc0[0] * u3 ] ++ movdqa ru3,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r2, hc1[0] * u2 ] ++ movdqa ru2,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r1, hc2[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * r0, hc3[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s4, hc4[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d3 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d3 ++ ++ # t1 = [ hc0[1] * r4, hc0[0] * u4 ] ++ movdqa ru4,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r3, hc1[0] * u3 ] ++ movdqa ru3,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r2, hc2[0] * u2 ] ++ movdqa ru2,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * r1, hc3[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * r0, hc4[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d4 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x20,m ++ dec %rcx ++ jnz .Ldoblock2 ++ ++ pop %r13 ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_2block_sse2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/Makefile 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,36 @@ ++ccflags-y := -O3 -fvisibility=hidden ++ccflags-$(CONFIG_WIREGUARD_DEBUG) := -DDEBUG -g ++ccflags-y += -Wframe-larger-than=8192 ++ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' ++wireguard-y := main.o noise.o device.o peer.o timers.o data.o send.o receive.o socket.o config.o hashtables.o routingtable.o ratelimiter.o cookie.o ++wireguard-y += crypto/curve25519.o crypto/chacha20poly1305.o crypto/blake2s.o ++ifeq ($(CONFIG_X86_64),y) ++ wireguard-y += crypto/chacha20-ssse3-x86_64.o crypto/poly1305-sse2-x86_64.o ++avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1$(comma)4)$(comma)%ymm2,yes,no) ++ifeq ($(avx2_supported),yes) ++ wireguard-y += crypto/chacha20-avx2-x86_64.o crypto/poly1305-avx2-x86_64.o ++endif ++endif ++ ++include $(src)/compat/Makefile.include ++ ++ifneq ($(KBUILD_EXTMOD),) ++CONFIG_WIREGUARD := m ++ifeq ($(CONFIG_WIREGUARD_PARALLEL),) ++ifneq (,$(filter $(CONFIG_PADATA),y m)) ++ccflags-y += -DCONFIG_WIREGUARD_PARALLEL=y ++endif ++endif ++ifneq ($(CONFIG_MODULES),) ++ifeq ($(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT),) ++$(error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT to be configured in your kernel. See https://www.wireguard.io/install/#kernel-requirements for more info") ++endif ++ifeq ($(CONFIG_PADATA),) ++ifneq ($(CONFIG_SMP),) ++$(warning "PEFORMANCE WARNING: WireGuard has enormous speed benefits when using CONFIG_PADATA on SMP systems. Please enable CONFIG_PADATA in your kernel configuration. See https://www.wireguard.io/install/#kernel-requirements for more info.") ++endif ++endif ++endif ++endif ++ ++obj-$(CONFIG_WIREGUARD) := wireguard.o +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/Kconfig 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,43 @@ ++config WIREGUARD ++ tristate "IP: WireGuard secure network tunnel" ++ depends on NET && INET ++ select NET_UDP_TUNNEL ++ select NETFILTER_XT_MATCH_HASHLIMIT ++ select NETFILTER ++ select NETFILTER_XTABLES ++ select NETFILTER_ADVANCED ++ select CRYPTO_BLKCIPHER ++ select IP6_NF_IPTABLES if IPV6 ++ default m ++ ---help--- ++ WireGuard is a secure, fast, and easy to use replacement for IPSec ++ that uses modern cryptography and clever networking tricks. It's ++ designed to be fairly general purpose and abstract enough to fit most ++ use cases, while at the same time remaining extremely simple to ++ configure. See www.wireguard.io for more info. ++ ++ It's safe to say Y or M here, as the driver is very lightweight and ++ is only in use when an administrator chooses to add an interface. ++ ++config WIREGUARD_PARALLEL ++ bool "Enable parallel engine" ++ depends on SMP && WIREGUARD ++ select PADATA ++ default y ++ ---help--- ++ This will allow WireGuard to utilize all CPU cores when encrypting ++ and decrypting packets. ++ ++ It's safe to say Y here, and you probably should, as the performance ++ improvements are substantial. ++ ++config WIREGUARD_DEBUG ++ bool "Debugging checks and verbose messages" ++ depends on WIREGUARD ++ ---help--- ++ This will write log messages for handshake and other events ++ that occur for a WireGuard interface. It will also perform some ++ extra validation checks and unit tests at various points. This is ++ only useful for debugging. ++ ++ Say N here unless you know what you're doing. +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/Makefile.include 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,11 @@ ++ccflags-y += -include $(src)/compat/compat.h ++ ++ifeq ($(wildcard $(srctree)/include/linux/siphash.h),) ++ccflags-y += -I$(src)/compat/siphash/include ++wireguard-y += compat/siphash/siphash.o ++endif ++ ++ifeq ($(wildcard $(srctree)/include/net/dst_cache.h),) ++ccflags-y += -I$(src)/compat/dst_cache/include ++wireguard-y += compat/dst_cache/dst_cache.o ++endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/compat.h 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,198 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef COMPAT_H ++#define COMPAT_H ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) ++#error "WireGuard requires Linux >= 3.18" ++#endif ++ ++/* These conditionals can't be enforced by an out of tree module very easily, ++ * so we stick them here in compat instead. */ ++#if !IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) ++#error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT." ++#endif ++#if IS_ENABLED(CONFIG_IPV6) && !IS_ENABLED(CONFIG_IP6_NF_IPTABLES) ++#error "WireGuard requires CONFIG_IP6_NF_IPTABLES when using CONFIG_IPV6." ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) && !defined(DEBUG) && defined(net_dbg_ratelimited) ++#undef net_dbg_ratelimited ++#define net_dbg_ratelimited(fmt, ...) do { if (0) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#define RCU_LOCKDEP_WARN(cond, message) rcu_lockdep_assert(!(cond), message) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 6)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 12) ++#define dev_recursion_level() 0 ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) ++#include ++#include ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; ret__ = udp_tunnel_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, i, j, k); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#if IS_ENABLED(CONFIG_IPV6) ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, j, k); ++#endif ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) ++#include ++#include ++static inline void fake_destructor(struct sk_buff *skb) ++{ ++} ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; (c)->destructor = fake_destructor; (c)->sk = (b); ret__ = udp_tunnel_xmit_skb(a, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#if IS_ENABLED(CONFIG_IPV6) ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { (c)->destructor = fake_destructor; (c)->sk = (b); udp_tunnel6_xmit_skb(a, c, d, e, f, g, h, j, k, l); } while(0) ++#endif ++#else ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) ++#include ++#include ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__ = udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, j, k, l) ++#endif ++ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#include ++#include ++struct udp_port_cfg_new { ++ u8 family; ++ union { ++ struct in_addr local_ip; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct in6_addr local_ip6; ++#endif ++ }; ++ union { ++ struct in_addr peer_ip; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct in6_addr peer_ip6; ++#endif ++ }; ++ __be16 local_udp_port; ++ __be16 peer_udp_port; ++ unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, use_udp6_rx_checksums:1, ipv6_v6only:1; ++}; ++static inline int __maybe_unused udp_sock_create_new(struct net *net, struct udp_port_cfg_new *cfg, struct socket **sockp) ++{ ++ struct udp_port_cfg old_cfg = { ++ .family = cfg->family, ++ .local_ip = cfg->local_ip, ++#if IS_ENABLED(CONFIG_IPV6) ++ .local_ip6 = cfg->local_ip6, ++#endif ++ .peer_ip = cfg->peer_ip, ++#if IS_ENABLED(CONFIG_IPV6) ++ .peer_ip6 = cfg->peer_ip6, ++#endif ++ .local_udp_port = cfg->local_udp_port, ++ .peer_udp_port = cfg->peer_udp_port, ++ .use_udp_checksums = cfg->use_udp_checksums, ++ .use_udp6_tx_checksums = cfg->use_udp6_tx_checksums, ++ .use_udp6_rx_checksums = cfg->use_udp6_rx_checksums ++ }; ++ if (cfg->family == AF_INET) ++ return udp_sock_create4(net, &old_cfg, sockp); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (cfg->family == AF_INET6) { ++ int ret; ++ int old_bindv6only; ++ struct net *nobns; ++ ++ if (cfg->ipv6_v6only) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++ nobns = &init_net; ++#else ++ nobns = net; ++#endif ++ /* Since udp_port_cfg only learned of ipv6_v6only in 4.3, we do this horrible ++ * hack here and set the sysctl variable temporarily to something that will ++ * set the right option for us in sock_create. It's super racey! */ ++ old_bindv6only = nobns->ipv6.sysctl.bindv6only; ++ nobns->ipv6.sysctl.bindv6only = 1; ++ } ++ ret = udp_sock_create6(net, &old_cfg, sockp); ++ if (cfg->ipv6_v6only) ++ nobns->ipv6.sysctl.bindv6only = old_bindv6only; ++ return ret; ++ } ++#endif ++ return -EPFNOSUPPORT; ++} ++#define udp_port_cfg udp_port_cfg_new ++#define udp_sock_create(a, b, c) udp_sock_create_new(a, b, c) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#define ipv6_dst_lookup(a, b, c, d) ipv6_dst_lookup(b, c, d) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 5) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 17) && LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 27) ++#define IP6_ECN_set_ce(a, b) IP6_ECN_set_ce(b) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) ++#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a) ++#define time_is_after_jiffies64(a) time_before64(get_jiffies_64(), a) ++#define time_is_before_eq_jiffies64(a) time_after_eq64(get_jiffies_64(), a) ++#define time_is_after_eq_jiffies64(a) time_before_eq64(get_jiffies_64(), a) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && IS_ENABLED(CONFIG_IPV6) ++#include ++static inline bool ipv6_mod_enabled(void) ++{ ++ return ipv6_stub->udpv6_encap_enable != NULL; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++#include ++static inline void skb_reset_tc(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_verd = 0; ++#endif ++} ++#endif ++ ++/* https://lkml.org/lkml/2015/6/12/415 */ ++#include ++static inline struct net_device *netdev_pub(void *dev) ++{ ++ return (struct net_device *)((char *)dev - ALIGN(sizeof(struct net_device), NETDEV_ALIGN)); ++} ++ ++/* PaX compatibility */ ++#ifdef CONSTIFY_PLUGIN ++#include ++#undef __read_mostly ++#define __read_mostly ++#endif ++ ++#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) ++#define net_dbg_skb_ratelimited(fmt, skb, ...) do { \ ++ struct endpoint __endpoint; \ ++ socket_endpoint_from_skb(&__endpoint, skb); \ ++ net_dbg_ratelimited(fmt, &__endpoint.addr, ##__VA_ARGS__); \ ++} while(0) ++#else ++#define net_dbg_skb_ratelimited(fmt, skb, ...) ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/siphash/include/linux/siphash.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,140 @@ ++/* Copyright (C) 2016 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This file is provided under a dual BSD/GPLv2 license. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4 for a secure PRF ++ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for ++ * hashtables. ++ */ ++ ++#ifndef _LINUX_SIPHASH_H ++#define _LINUX_SIPHASH_H ++ ++#include ++#include ++ ++#define SIPHASH_ALIGNMENT __alignof__(u64) ++typedef struct { ++ u64 key[2]; ++} siphash_key_t; ++ ++u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key); ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key); ++#endif ++ ++u64 siphash_1u64(const u64 a, const siphash_key_t *key); ++u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key); ++u64 siphash_3u64(const u64 a, const u64 b, const u64 c, ++ const siphash_key_t *key); ++u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d, ++ const siphash_key_t *key); ++u64 siphash_1u32(const u32 a, const siphash_key_t *key); ++u64 siphash_3u32(const u32 a, const u32 b, const u32 c, ++ const siphash_key_t *key); ++ ++static inline u64 siphash_2u32(const u32 a, const u32 b, ++ const siphash_key_t *key) ++{ ++ return siphash_1u64((u64)b << 32 | a, key); ++} ++static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c, ++ const u32 d, const siphash_key_t *key) ++{ ++ return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key); ++} ++ ++ ++static inline u64 ___siphash_aligned(const __le64 *data, size_t len, ++ const siphash_key_t *key) ++{ ++ if (__builtin_constant_p(len) && len == 4) ++ return siphash_1u32(le32_to_cpup((const __le32 *)data), key); ++ if (__builtin_constant_p(len) && len == 8) ++ return siphash_1u64(le64_to_cpu(data[0]), key); ++ if (__builtin_constant_p(len) && len == 16) ++ return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ key); ++ if (__builtin_constant_p(len) && len == 24) ++ return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ le64_to_cpu(data[2]), key); ++ if (__builtin_constant_p(len) && len == 32) ++ return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ le64_to_cpu(data[2]), le64_to_cpu(data[3]), ++ key); ++ return __siphash_aligned(data, len, key); ++} ++ ++/** ++ * siphash - compute 64-bit siphash PRF value ++ * @data: buffer to hash ++ * @size: size of @data ++ * @key: the siphash key ++ */ ++static inline u64 siphash(const void *data, size_t len, ++ const siphash_key_t *key) ++{ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT)) ++ return __siphash_unaligned(data, len, key); ++#endif ++ return ___siphash_aligned(data, len, key); ++} ++ ++#define HSIPHASH_ALIGNMENT __alignof__(unsigned long) ++typedef struct { ++ unsigned long key[2]; ++} hsiphash_key_t; ++ ++u32 __hsiphash_aligned(const void *data, size_t len, ++ const hsiphash_key_t *key); ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key); ++#endif ++ ++u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key); ++u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key); ++u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c, ++ const hsiphash_key_t *key); ++u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d, ++ const hsiphash_key_t *key); ++ ++static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ if (__builtin_constant_p(len) && len == 4) ++ return hsiphash_1u32(le32_to_cpu(data[0]), key); ++ if (__builtin_constant_p(len) && len == 8) ++ return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ key); ++ if (__builtin_constant_p(len) && len == 12) ++ return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ le32_to_cpu(data[2]), key); ++ if (__builtin_constant_p(len) && len == 16) ++ return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ le32_to_cpu(data[2]), le32_to_cpu(data[3]), ++ key); ++ return __hsiphash_aligned(data, len, key); ++} ++ ++/** ++ * hsiphash - compute 32-bit hsiphash PRF value ++ * @data: buffer to hash ++ * @size: size of @data ++ * @key: the hsiphash key ++ */ ++static inline u32 hsiphash(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT)) ++ return __hsiphash_unaligned(data, len, key); ++#endif ++ return ___hsiphash_aligned(data, len, key); ++} ++ ++#endif /* _LINUX_SIPHASH_H */ +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/siphash/siphash.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,551 @@ ++/* Copyright (C) 2016 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This file is provided under a dual BSD/GPLv2 license. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4 for a secure PRF ++ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for ++ * hashtables. ++ */ ++ ++#include ++#include ++ ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++#include ++#include ++#endif ++ ++#define SIPROUND \ ++ do { \ ++ v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \ ++ v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \ ++ v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \ ++ v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \ ++ } while (0) ++ ++#define PREAMBLE(len) \ ++ u64 v0 = 0x736f6d6570736575ULL; \ ++ u64 v1 = 0x646f72616e646f6dULL; \ ++ u64 v2 = 0x6c7967656e657261ULL; \ ++ u64 v3 = 0x7465646279746573ULL; \ ++ u64 b = ((u64)(len)) << 56; \ ++ v3 ^= key->key[1]; \ ++ v2 ^= key->key[0]; \ ++ v1 ^= key->key[1]; \ ++ v0 ^= key->key[0]; ++ ++#define POSTAMBLE \ ++ v3 ^= b; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ return (v0 ^ v1) ^ (v2 ^ v3); ++ ++u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ PREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = le64_to_cpup(data); ++ v3 ^= m; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= le32_to_cpup(data); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ POSTAMBLE ++} ++EXPORT_SYMBOL(__siphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ PREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = get_unaligned_le64(data); ++ v3 ^= m; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= get_unaligned_le32(end); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ POSTAMBLE ++} ++EXPORT_SYMBOL(__siphash_unaligned); ++#endif ++ ++/** ++ * siphash_1u64 - compute 64-bit siphash PRF value of a u64 ++ * @first: first u64 ++ * @key: the siphash key ++ */ ++u64 siphash_1u64(const u64 first, const siphash_key_t *key) ++{ ++ PREAMBLE(8) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_1u64); ++ ++/** ++ * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @key: the siphash key ++ */ ++u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key) ++{ ++ PREAMBLE(16) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_2u64); ++ ++/** ++ * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @third: third u64 ++ * @key: the siphash key ++ */ ++u64 siphash_3u64(const u64 first, const u64 second, const u64 third, ++ const siphash_key_t *key) ++{ ++ PREAMBLE(24) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= third; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_3u64); ++ ++/** ++ * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @third: third u64 ++ * @forth: forth u64 ++ * @key: the siphash key ++ */ ++u64 siphash_4u64(const u64 first, const u64 second, const u64 third, ++ const u64 forth, const siphash_key_t *key) ++{ ++ PREAMBLE(32) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= third; ++ v3 ^= forth; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= forth; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_4u64); ++ ++u64 siphash_1u32(const u32 first, const siphash_key_t *key) ++{ ++ PREAMBLE(4) ++ b |= first; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_1u32); ++ ++u64 siphash_3u32(const u32 first, const u32 second, const u32 third, ++ const siphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ PREAMBLE(12) ++ v3 ^= combined; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= combined; ++ b |= third; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_3u32); ++ ++#if BITS_PER_LONG == 64 ++/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for ++ * performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3. ++ */ ++ ++#define HSIPROUND SIPROUND ++#define HPREAMBLE(len) PREAMBLE(len) ++#define HPOSTAMBLE \ ++ v3 ^= b; \ ++ HSIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ return (v0 ^ v1) ^ (v2 ^ v3); ++ ++u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = le64_to_cpup(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= le32_to_cpup(data); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = get_unaligned_le64(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= get_unaligned_le32(end); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_unaligned); ++#endif ++ ++/** ++ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32 ++ * @first: first u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(4) ++ b |= first; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_1u32); ++ ++/** ++ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(8) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_2u32); ++ ++/** ++ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third, ++ const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(12) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ b |= third; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_3u32); ++ ++/** ++ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @forth: forth u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third, ++ const u32 forth, const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(16) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ combined = (u64)forth << 32 | third; ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_4u32); ++#else ++#define HSIPROUND \ ++ do { \ ++ v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \ ++ v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \ ++ v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \ ++ v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \ ++ } while (0) ++ ++#define HPREAMBLE(len) \ ++ u32 v0 = 0; \ ++ u32 v1 = 0; \ ++ u32 v2 = 0x6c796765U; \ ++ u32 v3 = 0x74656462U; \ ++ u32 b = ((u32)(len)) << 24; \ ++ v3 ^= key->key[1]; \ ++ v2 ^= key->key[0]; \ ++ v1 ^= key->key[1]; \ ++ v0 ^= key->key[0]; ++ ++#define HPOSTAMBLE \ ++ v3 ^= b; \ ++ HSIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ return v1 ^ v3; ++ ++u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u32)); ++ const u8 left = len & (sizeof(u32) - 1); ++ u32 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u32)) { ++ m = le32_to_cpup(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++ switch (left) { ++ case 3: b |= ((u32)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u32)); ++ const u8 left = len & (sizeof(u32) - 1); ++ u32 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u32)) { ++ m = get_unaligned_le32(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++ switch (left) { ++ case 3: b |= ((u32)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_unaligned); ++#endif ++ ++/** ++ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32 ++ * @first: first u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(4) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_1u32); ++ ++/** ++ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(8) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_2u32); ++ ++/** ++ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third, ++ const hsiphash_key_t *key) ++{ ++ HPREAMBLE(12) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ HSIPROUND; ++ v0 ^= third; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_3u32); ++ ++/** ++ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @forth: forth u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third, ++ const u32 forth, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(16) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ HSIPROUND; ++ v0 ^= third; ++ v3 ^= forth; ++ HSIPROUND; ++ v0 ^= forth; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_4u32); ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/dst_cache/include/net/dst_cache.h 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,97 @@ ++#ifndef _NET_DST_CACHE_H ++#define _NET_DST_CACHE_H ++ ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct dst_cache { ++ struct dst_cache_pcpu __percpu *cache; ++ unsigned long reset_ts; ++}; ++ ++/** ++ * dst_cache_get - perform cache lookup ++ * @dst_cache: the cache ++ * ++ * The caller should use dst_cache_get_ip4() if it need to retrieve the ++ * source address to be used when xmitting to the cached dst. ++ * local BH must be disabled. ++ */ ++struct dst_entry *dst_cache_get(struct dst_cache *dst_cache); ++ ++/** ++ * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address ++ * @dst_cache: the cache ++ * @saddr: return value for the retrieved source address ++ * ++ * local BH must be disabled. ++ */ ++struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr); ++ ++/** ++ * dst_cache_set_ip4 - store the ipv4 dst into the cache ++ * @dst_cache: the cache ++ * @dst: the entry to be cached ++ * @saddr: the source address to be stored inside the cache ++ * ++ * local BH must be disabled. ++ */ ++void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, ++ __be32 saddr); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++/** ++ * dst_cache_set_ip6 - store the ipv6 dst into the cache ++ * @dst_cache: the cache ++ * @dst: the entry to be cached ++ * @saddr: the source address to be stored inside the cache ++ * ++ * local BH must be disabled. ++ */ ++void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, ++ const struct in6_addr *addr); ++ ++/** ++ * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address ++ * @dst_cache: the cache ++ * @saddr: return value for the retrieved source address ++ * ++ * local BH must be disabled. ++ */ ++struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, ++ struct in6_addr *saddr); ++#endif ++ ++/** ++ * dst_cache_reset - invalidate the cache contents ++ * @dst_cache: the cache ++ * ++ * This do not free the cached dst to avoid races and contentions. ++ * the dst will be freed on later cache lookup. ++ */ ++static inline void dst_cache_reset(struct dst_cache *dst_cache) ++{ ++ dst_cache->reset_ts = jiffies; ++} ++ ++/** ++ * dst_cache_init - initialize the cache, allocating the required storage ++ * @dst_cache: the cache ++ * @gfp: allocation flags ++ */ ++int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp); ++ ++/** ++ * dst_cache_destroy - empty the cache and free the allocated storage ++ * @dst_cache: the cache ++ * ++ * No synchronization is enforced: it must be called only when the cache ++ * is unsed. ++ */ ++void dst_cache_destroy(struct dst_cache *dst_cache); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/dst_cache/dst_cache.c 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,177 @@ ++/* ++ * net/core/dst_cache.c - dst entry cache ++ * ++ * Copyright (c) 2016 Paolo Abeni ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++static inline u32 rt6_get_cookie(const struct rt6_info *rt) ++{ ++ if ((unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from)) ++ rt = (struct rt6_info *)(rt->dst.from); ++ ++ return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; ++} ++#endif ++#endif ++#include ++ ++struct dst_cache_pcpu { ++ unsigned long refresh_ts; ++ struct dst_entry *dst; ++ u32 cookie; ++ union { ++ struct in_addr in_saddr; ++ struct in6_addr in6_saddr; ++ }; ++}; ++ ++static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache, ++ struct dst_entry *dst, u32 cookie) ++{ ++ dst_release(dst_cache->dst); ++ if (dst) ++ dst_hold(dst); ++ ++ dst_cache->cookie = cookie; ++ dst_cache->dst = dst; ++} ++ ++static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache, ++ struct dst_cache_pcpu *idst) ++{ ++ struct dst_entry *dst; ++ ++ dst = idst->dst; ++ if (!dst) ++ goto fail; ++ ++ /* the cache already hold a dst reference; it can't go away */ ++ dst_hold(dst); ++ ++ if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) || ++ (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) { ++ dst_cache_per_cpu_dst_set(idst, NULL, 0); ++ dst_release(dst); ++ goto fail; ++ } ++ return dst; ++ ++fail: ++ idst->refresh_ts = jiffies; ++ return NULL; ++} ++ ++struct dst_entry *dst_cache_get(struct dst_cache *dst_cache) ++{ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache)); ++} ++EXPORT_SYMBOL_GPL(dst_cache_get); ++ ++struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ struct dst_entry *dst; ++ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst = dst_cache_per_cpu_get(dst_cache, idst); ++ if (!dst) ++ return NULL; ++ ++ *saddr = idst->in_saddr.s_addr; ++ return container_of(dst, struct rtable, dst); ++} ++EXPORT_SYMBOL_GPL(dst_cache_get_ip4); ++ ++void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, ++ __be32 saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst_cache_per_cpu_dst_set(idst, dst, 0); ++ idst->in_saddr.s_addr = saddr; ++} ++EXPORT_SYMBOL_GPL(dst_cache_set_ip4); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, ++ const struct in6_addr *addr) ++{ ++ struct dst_cache_pcpu *idst; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst, ++ rt6_get_cookie((struct rt6_info *)dst)); ++ idst->in6_saddr = *addr; ++} ++EXPORT_SYMBOL_GPL(dst_cache_set_ip6); ++ ++struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, ++ struct in6_addr *saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ struct dst_entry *dst; ++ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst = dst_cache_per_cpu_get(dst_cache, idst); ++ if (!dst) ++ return NULL; ++ ++ *saddr = idst->in6_saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(dst_cache_get_ip6); ++#endif ++ ++int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp) ++{ ++ dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu, ++ gfp | __GFP_ZERO); ++ if (!dst_cache->cache) ++ return -ENOMEM; ++ ++ dst_cache_reset(dst_cache); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dst_cache_init); ++ ++void dst_cache_destroy(struct dst_cache *dst_cache) ++{ ++ int i; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ for_each_possible_cpu(i) ++ dst_release(per_cpu_ptr(dst_cache->cache, i)->dst); ++ ++ free_percpu(dst_cache->cache); ++} ++EXPORT_SYMBOL_GPL(dst_cache_destroy); +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -85,2 +85,3 @@ config INET + if INET ++source "net/wireguard/Kconfig" + source "net/ipv4/Kconfig" +--- a/net/Makefile ++++ b/net/Makefile +@@ -16,2 +16,3 @@ + obj-$(CONFIG_NETFILTER) += netfilter/ ++obj-$(CONFIG_WIREGUARD) += wireguard/ + obj-$(CONFIG_INET) += ipv4/ diff --git a/kernel/kernel/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch b/kernel/kernel/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch deleted file mode 100644 index cee31761..00000000 --- a/kernel/kernel/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch +++ /dev/null @@ -1,29 +0,0 @@ - -From: Gavin Li - -brcmf_sdio_fromevntchan() was being called on the the data frame -rather than the software header, causing some frames to be -mischaracterized as on the event channel rather than the data channel. - -This fixes a major performance regression (due to dropped packets). - -Fixes: c56caa9db8ab ("brcmfmac: screening firmware event packet") -Signed-off-by: Gavin Li -Cc: [4.7+] ---- - drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -index dfb0658713d9..d2219885071f 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -1661,7 +1661,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) - pfirst->len, pfirst->next, - pfirst->prev); - skb_unlink(pfirst, &bus->glom); -- if (brcmf_sdio_fromevntchan(pfirst->data)) -+ if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN])) - brcmf_rx_event(bus->sdiodev->dev, pfirst); - else - brcmf_rx_frame(bus->sdiodev->dev, pfirst, diff --git a/kernel/kernel/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch b/kernel/kernel/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch new file mode 100644 index 00000000..6f7092cc --- /dev/null +++ b/kernel/kernel/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch @@ -0,0 +1,371 @@ + +From upstream 4.11-rc2+ git + +Fixes mga #20508 + +Signed-off-by: Thomas Backlund + + + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 29 ++-- + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 4 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_872tb.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 121 +++++++++++------ + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 + 7 files changed, 105 insertions(+), 57 deletions(-) + +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c 2017-03-07 22:29:07.840867965 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8188c/8188r/8192c specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8192e specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +@@ -1556,7 +1556,7 @@ exit: + return ret; + } + +-void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) ++static void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) + { + u8 val8; + u16 val16; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8723a specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8723b specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c 2017-03-18 13:35:47.148080457 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +@@ -48,7 +48,7 @@ static bool rtl8xxxu_dma_aggregation; + static int rtl8xxxu_dma_agg_timeout = -1; + static int rtl8xxxu_dma_agg_pages = -1; + +-MODULE_AUTHOR("Jes Sorensen "); ++MODULE_AUTHOR("Jes Sorensen "); + MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver"); + MODULE_LICENSE("GPL"); + MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); +@@ -4767,13 +4767,28 @@ static void rtl8xxxu_dump_action(struct + * This format is used on 8188cu/8192cu/8723au + */ + void +-rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable) ++rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, u32 rts_rate) + { ++ struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); ++ struct rtl8xxxu_priv *priv = hw->priv; ++ struct device *dev = &priv->udev->dev; ++ u32 rate; ++ u16 rate_flags = tx_info->control.rates[0].flags; + u16 seq_number; + ++ if (rate_flags & IEEE80211_TX_RC_MCS && ++ !ieee80211_is_mgmt(hdr->frame_control)) ++ rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; ++ else ++ rate = tx_rate->hw_value; ++ ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) ++ dev_info(dev, "%s: TX rate: %d, pkt size %d\n", ++ __func__, rate, cpu_to_le16(tx_desc->pkt_size)); ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + tx_desc->txdw5 = cpu_to_le32(rate); +@@ -4804,15 +4819,16 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211 + if (sgi) + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI); + +- if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { +- /* +- * Use RTS rate 24M - does the mac80211 tell +- * us which to use? +- */ +- tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M << +- TXDESC32_RTS_RATE_SHIFT); ++ /* ++ * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled ++ */ ++ tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); ++ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); ++ } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ++ tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); ++ tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } + } + +@@ -4821,16 +4837,31 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211 + * This format is used on 8192eu/8723bu + */ + void +-rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable) ++rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, ++ bool short_preamble, bool ampdu_enable, u32 rts_rate) + { ++ struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); ++ struct rtl8xxxu_priv *priv = hw->priv; ++ struct device *dev = &priv->udev->dev; + struct rtl8xxxu_txdesc40 *tx_desc40; ++ u32 rate; ++ u16 rate_flags = tx_info->control.rates[0].flags; + u16 seq_number; + + tx_desc40 = (struct rtl8xxxu_txdesc40 *)tx_desc32; + ++ if (rate_flags & IEEE80211_TX_RC_MCS && ++ !ieee80211_is_mgmt(hdr->frame_control)) ++ rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; ++ else ++ rate = tx_rate->hw_value; ++ ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) ++ dev_info(dev, "%s: TX rate: %d, pkt size %d\n", ++ __func__, rate, cpu_to_le16(tx_desc40->pkt_size)); ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + tx_desc40->txdw4 = cpu_to_le32(rate); +@@ -4857,15 +4888,19 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211 + if (short_preamble) + tx_desc40->txdw5 |= cpu_to_le32(TXDESC40_SHORT_PREAMBLE); + +- if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { +- /* +- * Use RTS rate 24M - does the mac80211 tell +- * us which to use? +- */ +- tx_desc40->txdw4 |= cpu_to_le32(DESC_RATE_24M << +- TXDESC40_RTS_RATE_SHIFT); ++ tx_desc40->txdw4 |= cpu_to_le32(rts_rate << TXDESC40_RTS_RATE_SHIFT); ++ /* ++ * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled ++ */ ++ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_RTS_CTS_ENABLE); + tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_HW_RTS_ENABLE); ++ } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ++ /* ++ * For some reason the vendor driver doesn't set ++ * TXDESC40_HW_RTS_ENABLE for CTS to SELF ++ */ ++ tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_CTS_SELF_ENABLE); + } + } + +@@ -4875,14 +4910,13 @@ static void rtl8xxxu_tx(struct ieee80211 + { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); +- struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); + struct rtl8xxxu_priv *priv = hw->priv; + struct rtl8xxxu_txdesc32 *tx_desc; + struct rtl8xxxu_tx_urb *tx_urb; + struct ieee80211_sta *sta = NULL; + struct ieee80211_vif *vif = tx_info->control.vif; + struct device *dev = &priv->udev->dev; +- u32 queue, rate; ++ u32 queue, rts_rate; + u16 pktlen = skb->len; + u16 seq_number; + u16 rate_flag = tx_info->control.rates[0].flags; +@@ -4909,10 +4943,6 @@ static void rtl8xxxu_tx(struct ieee80211 + goto error; + } + +- if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) +- dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n", +- __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen); +- + if (ieee80211_is_action(hdr->frame_control)) + rtl8xxxu_dump_action(dev, hdr); + +@@ -4966,12 +4996,6 @@ static void rtl8xxxu_tx(struct ieee80211 + } + } + +- if (rate_flag & IEEE80211_TX_RC_MCS && +- !ieee80211_is_mgmt(hdr->frame_control)) +- rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; +- else +- rate = tx_rate->hw_value; +- + if (rate_flag & IEEE80211_TX_RC_SHORT_GI || + (ieee80211_is_data_qos(hdr->frame_control) && + sta && sta->ht_cap.cap & +@@ -4982,10 +5006,17 @@ static void rtl8xxxu_tx(struct ieee80211 + (sta && vif && vif->bss_conf.use_short_preamble)) + short_preamble = true; + ++ if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) ++ rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; ++ else if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) ++ rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; ++ else ++ rts_rate = 0; ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + +- priv->fops->fill_txdesc(hdr, tx_desc, rate, rate_flag, +- sgi, short_preamble, ampdu_enable); ++ priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, ++ ampdu_enable, rts_rate); + + rtl8xxxu_calc_tx_desc_csum(tx_desc); + +@@ -5969,6 +6000,7 @@ static int rtl8xxxu_probe(struct usb_int + case 0x8176: + case 0x8178: + case 0x817f: ++ case 0x818b: + untested = 0; + break; + } +@@ -6165,6 +6197,12 @@ static struct usb_device_id dev_table[] + .driver_info = (unsigned long)&rtl8723au_fops}, + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192eu_fops}, ++/* TP-Link TL-WN822N v4 */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0108, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++/* D-Link DWA-131 rev E1, tested by David Patiño */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3319, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, + /* Tested by Myckel Habets */ + {USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0109, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192eu_fops}, +@@ -6316,6 +6354,13 @@ static struct usb_device_id dev_table[] + .driver_info = (unsigned long)&rtl8192cu_fops}, + {USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, ++/* found in rtl8192eu vendor driver */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0107, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab33, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818c, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, + #endif + { } + }; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h 2017-03-07 22:29:07.840867965 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as +@@ -1337,10 +1337,11 @@ struct rtl8xxxu_fileops { + u32 ramask, int sgi); + void (*report_connect) (struct rtl8xxxu_priv *priv, + u8 macid, bool connect); +- void (*fill_txdesc) (struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); ++ void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); + int writeN_block_size; + int rx_agg_buf_size; + char tx_desc_size; +@@ -1434,14 +1435,16 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8x + int rtl8xxxu_gen2_channel_to_group(int channel); + bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2); +-void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); +-void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); ++void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); ++void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); + + extern struct rtl8xxxu_fileops rtl8192cu_fops; + extern struct rtl8xxxu_fileops rtl8192eu_fops; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h 2017-03-07 22:29:07.842868144 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as diff --git a/kernel/kernel/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch b/kernel/kernel/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch new file mode 100644 index 00000000..0383b3ba --- /dev/null +++ b/kernel/kernel/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch @@ -0,0 +1,43 @@ +From: Joerg Roedel + +ATS is broken on these devices. Under invalidation load, the +GPU does not reply to invalidations anymore, causing +Completion-wait loop timeouts on the AMD IOMMU driver side. +Fix it by not enabling ATS on these devices. + +Note that below mentioned commit is not broken, it just +triggers the issue because it might cause invalidation +storms on devices. + +Fixes: b1516a14657a ('iommu/amd: Implement flush queue') +Reported-by: Daniel Drake +Cc: Daniel Drake +Cc: Alexander Deucher +Signed-off-by: Joerg Roedel +--- + drivers/pci/ats.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c +index eeb9fb2..711bdb2 100644 +--- a/drivers/pci/ats.c ++++ b/drivers/pci/ats.c +@@ -17,10 +17,18 @@ + + #include "pci.h" + ++static const struct pci_device_id broken_ats_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x98e4) }, /* AMD Stoney GPU part */ ++ { 0 } ++}; ++ + void pci_ats_init(struct pci_dev *dev) + { + int pos; + ++ if (pci_match_id(broken_ats_tbl, dev)) ++ return; ++ + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); + if (!pos) + return; diff --git a/kernel/kernel/files/patches/mageia/series b/kernel/kernel/files/patches/mageia/series index ca9b5050..92c06398 100644 --- a/kernel/kernel/files/patches/mageia/series +++ b/kernel/kernel/files/patches/mageia/series @@ -14,14 +14,7 @@ ### ### Stable Queue ### - -# CVE-2016-8405 -stable-fbdev-color-map-copying-bounds-checking.patch - -stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch -stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch -stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch -stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch +patch-4.9.19-rc1.patch ### ### Arch x86 @@ -46,9 +39,6 @@ x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch # slows down boot Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch -# breaks nvidia304 -Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch - ### ### Core ### @@ -68,6 +58,9 @@ base-cacheinfo-silence-DT-warnings.patch pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch pci-quirks-drop-devinit-exit.patch +# Stoney iommu hang +pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch + ### ### PNP core ### @@ -88,6 +81,9 @@ ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch # drop obsolete warn acpi-do-not-warn-if-_BQC-does-not-exist.patch +# silence useless acpi warnings +acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch + ### ### Block ### @@ -137,6 +133,9 @@ block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch block-Turn-into-BFQ-v8r6-for-4.9.0.patch +# new macbooks +block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch + ### ### Char ### @@ -194,11 +193,16 @@ gpu-drm-mach64-linux-3.14-buildfix.patch gpu-drm-mach64-3.17-buildfix.patch gpu-drm-mach64-3.18-buildfix.patch -# i915 skl/kbl speedup -gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch -gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch -gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch -gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch +# +gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch + +# Amd polaris12 support +gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch +gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch +gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch + +# fix crash +gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch ### ### Hardware Monitoring @@ -256,8 +260,11 @@ net-netfilter-psd-fix-redefines.patch net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch -# fix speed regression -net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch +# update rtl8xxxu for mga#20508 +net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch + +# WireGuard support +net-wireguard.patch ### ### Platform drivers @@ -284,6 +291,10 @@ include-kbuild-export-pci_ids.patch ### Sound ### +# new codecs +sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch +sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch + ### ### Staging ### diff --git a/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch b/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch new file mode 100644 index 00000000..ae18a31b --- /dev/null +++ b/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch @@ -0,0 +1,102 @@ +From 28f1f9b26cee161ddd3985b3eb78e3ffada08dda Mon Sep 17 00:00:00 2001 +From: Kailang Yang +Date: Wed, 4 Jan 2017 14:49:07 +0800 +Subject: [PATCH] ALSA: hda/realtek - Add new codec ID ALC299 + +ALC299 was similar as ALC225. +Add headset support for ALC299. +ALC3271 was for Dell rename. + +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_realtek.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 1ae29fd..3c69647 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + case 0x10ec0288: + case 0x10ec0295: + case 0x10ec0298: ++ case 0x10ec0299: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + break; + case 0x10ec0285: +@@ -912,6 +913,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { + { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, + { 0x10ec0295, 0x1028, 0, "ALC3254" }, ++ { 0x10ec0299, 0x1028, 0, "ALC3271" }, + { 0x10ec0670, 0x1025, 0, "ALC669X" }, + { 0x10ec0676, 0x1025, 0, "ALC679X" }, + { 0x10ec0282, 0x1043, 0, "ALC3229" }, +@@ -3716,6 +3718,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0867: +@@ -3823,6 +3826,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0225); +@@ -3881,6 +3885,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) + switch (codec->core.vendor_id) { + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0255: +@@ -3996,6 +4001,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0867: +@@ -4089,6 +4095,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + } +@@ -4173,6 +4180,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); +@@ -6219,6 +6227,7 @@ static int patch_alc269(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + spec->codec_variant = ALC269_TYPE_ALC225; + break; + case 0x10ec0234: +@@ -7256,6 +7265,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), ++ HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269), + HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), + HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), + HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch b/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch new file mode 100644 index 00000000..70646467 --- /dev/null +++ b/kernel/kernel/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch @@ -0,0 +1,45 @@ +From a535ad57d0e6b959cd79914a1127caade36a9459 Mon Sep 17 00:00:00 2001 +From: Kailang Yang +Date: Mon, 16 Jan 2017 16:59:26 +0800 +Subject: [PATCH] ALSA: hda/realtek - New codec support of ALC1220 + +Add support for new codec of ALC1220. +It's compatible with ALC882 & co. + +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_realtek.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 3c69647..1c88da8 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -380,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + break; + case 0x10ec0899: + case 0x10ec0900: ++ case 0x10ec1220: + alc_update_coef_idx(codec, 0x7, 1<<1, 0); + break; + } +@@ -2310,6 +2311,7 @@ static int patch_alc882(struct hda_codec *codec) + case 0x10ec0882: + case 0x10ec0885: + case 0x10ec0900: ++ case 0x10ec1220: + break; + default: + /* ALC883 and variants */ +@@ -7297,6 +7299,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), ++ HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), + {} /* terminator */ + }; + MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); +-- +2.10.2 + diff --git a/kernel/kernel/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch b/kernel/kernel/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch deleted file mode 100644 index 1e434efd..00000000 --- a/kernel/kernel/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch +++ /dev/null @@ -1,71 +0,0 @@ -From fdf35a6b22247746a7053fc764d04218a9306f82 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Mon, 9 Jan 2017 15:56:14 +0100 -Subject: drm: Fix broken VT switch with video=1366x768 option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -From: Takashi Iwai - -commit fdf35a6b22247746a7053fc764d04218a9306f82 upstream. - -I noticed that the VT switch doesn't work any longer with a Dell -laptop with 1366x768 eDP when the machine is connected with a DP -monitor. It behaves as if VT were switched, but the graphics remain -frozen. Actually the keyboard works, so I could switch back to VT7 -again. - -I tried to track down the problem, and encountered a long story until -we reach to this error: - -- The machine is booted with video=1366x768 option (the distro - installer seems to add it as default). -- Recently, drm_helper_probe_single_connector_modes() deals with - cmdline modes, and it tries to create a new mode when no - matching mode is found. -- The drm_mode_create_from_cmdline_mode() creates a mode based on - either CVT of GFT according to the given cmdline mode; in our case, - it's 1366x768. -- Since both CVT and GFT can't express the width 1366 due to - alignment, the resultant mode becomes 1368x768, slightly larger than - the given size. -- Later on, the atomic commit is performed, and in - drm_atomic_check_only(), the size of each plane is checked. -- The size check of 1366x768 fails due to the above, and eventually - the whole VT switch fails. - -Back in the history, we've had a manual fix-up of 1368x768 in various -places via c09dedb7a50e ("drm/edid: Add a workaround for 1366x768 HD -panel"), but they have been all in drm_edid.c at probing the modes -from EDID. For addressing the problem above, we need a similar hack -to the mode newly created from cmdline, manually adjusting the width -when the expected size is 1366 while we get 1368 instead. - -Fixes: eaf99c749d43 ("drm: Perform cmdline mode parsing during...") -Signed-off-by: Takashi Iwai -Link: http://patchwork.freedesktop.org/patch/msgid/20170109145614.29454-1-tiwai@suse.de -Reviewed-by: Ville Syrjälä -Signed-off-by: Ville Syrjälä -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/drm_modes.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/gpu/drm/drm_modes.c -+++ b/drivers/gpu/drm/drm_modes.c -@@ -1462,6 +1462,13 @@ drm_mode_create_from_cmdline_mode(struct - return NULL; - - mode->type |= DRM_MODE_TYPE_USERDEF; -+ /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */ -+ if (cmd->xres == 1366 && mode->hdisplay == 1368) { -+ mode->hdisplay = 1366; -+ mode->hsync_start--; -+ mode->hsync_end--; -+ drm_mode_set_name(mode); -+ } - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - return mode; - } diff --git a/kernel/kernel/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch b/kernel/kernel/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch deleted file mode 100644 index e1d1a683..00000000 --- a/kernel/kernel/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 3bfdfdcbce2796ce75bf2d85fd8471858d702e5d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= -Date: Mon, 7 Nov 2016 22:20:54 +0200 -Subject: drm/i915: Ignore bogus plane coordinates on SKL when the plane is not visible -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -From: Ville Syrjälä - -commit 3bfdfdcbce2796ce75bf2d85fd8471858d702e5d upstream. - -When the plane is invisible we may have all sorts of bogus stuff -in the coordinates, which we must ignore or else we might fail the -plane update. This started to happen on SKL when I moved the plane -offset computation to happen in the check phase. Previously we -happily ignored it all since we never called the update_plane hook -with an invisible plane. - -Cc: Sivakumar Thulasimani -Cc: drm-intel-fixes@lists.freedesktop.org -Fixes: b63a16f6cd89 ("drm/i915: Compute display surface offset in the plane check hook for SKL+") -Signed-off-by: Ville Syrjälä -Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98258 -Testcase: igt/pm_rpm/legacy-planes -Testcase: igt/pm_rpm/universal-planes -Reviewed-by: Matt Roper -Signed-off-by: Matt Roper -Link: http://patchwork.freedesktop.org/patch/msgid/1478550057-24864-3-git-send-email-ville.syrjala@linux.intel.com -(cherry picked from commit a5e4c7d0aa6784d8abe95c3ceef0da9656d17468) -Signed-off-by: Jani Nikula -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/i915/intel_display.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -2975,6 +2975,9 @@ int skl_check_plane_surface(struct intel - unsigned int rotation = plane_state->base.rotation; - int ret; - -+ if (!plane_state->base.visible) -+ return 0; -+ - /* Rotate src coordinates to match rotated GTT view */ - if (intel_rotation_90_or_270(rotation)) - drm_rect_rotate(&plane_state->base.src, diff --git a/kernel/kernel/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch b/kernel/kernel/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch deleted file mode 100644 index 7875c08d..00000000 --- a/kernel/kernel/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 68f458eec7069d618a6c884ca007426e0cea411b Mon Sep 17 00:00:00 2001 -From: Peter Ujfalusi -Date: Mon, 9 Jan 2017 16:31:58 +0200 -Subject: drm: Schedule the output_poll_work with 1s delay if we have delayed event - -From: Peter Ujfalusi - -commit 68f458eec7069d618a6c884ca007426e0cea411b upstream. - -Instead of scheduling the work to handle the initial delayed event, use 1s -delay. - -This delay should not be needed, but Optimus/nouveau will fail in a -mysterious way if the delayed event is handled as soon as possible like it -is done in drm_helper_probe_single_connector_modes() in case the poll -was enabled before. - -Reverting 339fd36238dd would give back the 10 sec (!) delay to handle the -delayed event. Adding 1sec delay to the poll_work is enough to work around -the issue in Optimus setups and gives shorter response on handling the -initial delayed event. - -Fixes: 339fd36238dd ("drm: drm_probe_helper: Fix output_poll_work scheduling") -Signed-off-by: Peter Ujfalusi -[danvet: Add FIXME to the comment to make it stick out more.] -Signed-off-by: Daniel Vetter -Link: http://patchwork.freedesktop.org/patch/msgid/20170109143158.21917-1-peter.ujfalusi@ti.com -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/drm_probe_helper.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/drm_probe_helper.c -+++ b/drivers/gpu/drm/drm_probe_helper.c -@@ -143,8 +143,18 @@ void drm_kms_helper_poll_enable_locked(s - } - - if (dev->mode_config.delayed_event) { -+ /* -+ * FIXME: -+ * -+ * Use short (1s) delay to handle the initial delayed event. -+ * This delay should not be needed, but Optimus/nouveau will -+ * fail in a mysterious way if the delayed event is handled as -+ * soon as possible like it is done in -+ * drm_helper_probe_single_connector_modes() in case the poll -+ * was enabled before. -+ */ - poll = true; -- delay = 0; -+ delay = HZ; - } - - if (poll) diff --git a/kernel/kernel/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch b/kernel/kernel/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch deleted file mode 100644 index be9e7b23..00000000 --- a/kernel/kernel/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 2dc705a9930b4806250fbf5a76e55266e59389f2 Mon Sep 17 00:00:00 2001 -From: Kees Cook -Date: Tue, 24 Jan 2017 15:18:24 -0800 -Subject: fbdev: color map copying bounds checking - -From: Kees Cook - -commit 2dc705a9930b4806250fbf5a76e55266e59389f2 upstream. - -Copying color maps to userspace doesn't check the value of to->start, -which will cause kernel heap buffer OOB read due to signedness wraps. - -CVE-2016-8405 - -Link: http://lkml.kernel.org/r/20170105224249.GA50925@beast -Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") -Signed-off-by: Kees Cook -Reported-by: Peter Pi (@heisecode) of Trend Micro -Cc: Min Chong -Cc: Dan Carpenter -Cc: Tomi Valkeinen -Cc: Bartlomiej Zolnierkiewicz -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/video/fbdev/core/fbcmap.c | 26 ++++++++++++++------------ - 1 file changed, 14 insertions(+), 12 deletions(-) - ---- a/drivers/video/fbdev/core/fbcmap.c -+++ b/drivers/video/fbdev/core/fbcmap.c -@@ -163,17 +163,18 @@ void fb_dealloc_cmap(struct fb_cmap *cma - - int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) - { -- int tooff = 0, fromoff = 0; -- int size; -+ unsigned int tooff = 0, fromoff = 0; -+ size_t size; - - if (to->start > from->start) - fromoff = to->start - from->start; - else - tooff = from->start - to->start; -- size = to->len - tooff; -- if (size > (int) (from->len - fromoff)) -- size = from->len - fromoff; -- if (size <= 0) -+ if (fromoff >= from->len || tooff >= to->len) -+ return -EINVAL; -+ -+ size = min_t(size_t, to->len - tooff, from->len - fromoff); -+ if (size == 0) - return -EINVAL; - size *= sizeof(u16); - -@@ -187,17 +188,18 @@ int fb_copy_cmap(const struct fb_cmap *f - - int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) - { -- int tooff = 0, fromoff = 0; -- int size; -+ unsigned int tooff = 0, fromoff = 0; -+ size_t size; - - if (to->start > from->start) - fromoff = to->start - from->start; - else - tooff = from->start - to->start; -- size = to->len - tooff; -- if (size > (int) (from->len - fromoff)) -- size = from->len - fromoff; -- if (size <= 0) -+ if (fromoff >= from->len || tooff >= to->len) -+ return -EINVAL; -+ -+ size = min_t(size_t, to->len - tooff, from->len - fromoff); -+ if (size == 0) - return -EINVAL; - size *= sizeof(u16); - diff --git a/kernel/kernel/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch b/kernel/kernel/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch deleted file mode 100644 index 454c386d..00000000 --- a/kernel/kernel/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch +++ /dev/null @@ -1,32 +0,0 @@ -From fd7c99142d77dc4a851879a66715abf12a3193fb Mon Sep 17 00:00:00 2001 -From: Dave Martin -Date: Fri, 6 Jan 2017 17:54:51 +0000 -Subject: tile/ptrace: Preserve previous registers for short regset write - -From: Dave Martin - -commit fd7c99142d77dc4a851879a66715abf12a3193fb upstream. - -Ensure that if userspace supplies insufficient data to -PTRACE_SETREGSET to fill all the registers, the thread's old -registers are preserved. - -Signed-off-by: Dave Martin -Signed-off-by: Chris Metcalf -Signed-off-by: Greg Kroah-Hartman - ---- - arch/tile/kernel/ptrace.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/tile/kernel/ptrace.c -+++ b/arch/tile/kernel/ptrace.c -@@ -111,7 +111,7 @@ static int tile_gpr_set(struct task_stru - const void *kbuf, const void __user *ubuf) - { - int ret; -- struct pt_regs regs; -+ struct pt_regs regs = *task_pt_regs(target); - - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, - sizeof(regs)); diff --git a/kernel/kernel/pspec.xml b/kernel/kernel/pspec.xml index 29a9d1e1..61c08238 100644 --- a/kernel/kernel/pspec.xml +++ b/kernel/kernel/pspec.xml @@ -28,25 +28,21 @@ - patches/linux/patch-4.9.6.xz - + patches/linux/patch-4.9.18.xz + - patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch - patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch - patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch - patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch - patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch - patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch patches/mageia/base-cacheinfo-silence-DT-warnings.patch patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch patches/mageia/pci-quirks-drop-devinit-exit.patch + patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch patches/mageia/acpi-processor-M720SR-limit-to-C2.patch patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch patches/mageia/acpi-do-not-warn-if-_BQC-does-not-exist.patch + patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch + patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch patches/mageia/char-tpm-tpm_crb-implement-tpm-crb-idle-state.patch patches/mageia/char-tmp-tpm_crb-fix-Intel-PTT-hw-bug-during-idle-state.patch patches/mageia/char-tpm-tpm_crb-open-code-the-crb_init-into-acpi_add.patch @@ -91,10 +88,11 @@ patches/mageia/gpu-drm-mach64-linux-3.14-buildfix.patch patches/mageia/gpu-drm-mach64-3.17-buildfix.patch patches/mageia/gpu-drm-mach64-3.18-buildfix.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch - patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch + patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch + patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch + patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch + patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch + patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch patches/mageia/net-sis190-fix-list-usage.patch patches/mageia/net-netfilter-IFWLOG.patch @@ -110,11 +108,14 @@ patches/mageia/net-netfilter-psd-fix-redefines.patch patches/mageia/net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch patches/mageia/net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch - patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch + patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch + patches/mageia/net-wireguard.patch patches/mageia/platform-x86-add-shuttle-wmi-driver.patch patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch patches/mageia/include-kbuild-export-pci_ids.patch + patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch + patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch patches/mageia/usb-storage-unusual_devs-add-id.patch patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch @@ -164,7 +165,6 @@ /boot /lib/modules /etc/kernel - /etc/mkinitcpio.d System.Package @@ -204,6 +204,17 @@ + + 2017-03-30 + 4.9.18 + Version Bump. + security + + systemRestart + + Ertuğrul Erata + ertugrulerata@gmail.com + 2017-01-27 4.9.6 diff --git a/kernel/tools/cpupowertools/files/patches/linux/patch-4.9.18.xz b/kernel/tools/cpupowertools/files/patches/linux/patch-4.9.18.xz new file mode 100644 index 0000000000000000000000000000000000000000..52032c3ccb5e508c2912404f3eb56089e795e703 GIT binary patch literal 412000 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

P8g#0@C0V92u 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⪙R# zZ~ONF!DW##R$}6ZFw*re+|!r{MDl}8AQFm)|G!)^MEBGQzxVHTyVvL0X;n3BTy+oG zuTk+_QAQD{E?m5FcW8kL!?s^{d$^Of_EYbey^U_^XS9citI2V2E;k6ppc^r#6JQ5OVvQjyXIF*2cbpv!~= z?!g#}Ol1sQo*+Ec}t_&*tfAvF^+QW*GCGI2{u;a8@ zrZ`rEyp5MtkQSBR| zyk6R8awwPqa~5y!?7a(x7fQlG@&Gq32arW}Ui9&SmD?ZM&BLw4WR+$SY?QMDK$0#; zh-M$D`Q$7pevt}WMqGJ*Cn@C|j2BSKaJ4H-4|;BYl8AVYWu&21-6PFdBq-sg?WRE@ z>yzg-<9JT*XUw(IIBTTX{dP{24gdTca4Va(dahSXsviK_L>b0jT4!DBu6TB~&lAW) zC}}p<*PG}0GDLpgpmN{0dEBq+Ui3;}-YS^ArIated|<$Gv!)uq`cJq)>L4ux4jlA} z@%jL6VCh)zx^&XS-}YRXU)6{2Vmlz67!l@EX} zM2zX1kS^%J)h{TBMpxsrhLyg~6B;t7JXv+fTXw@AMZf(k1ruSR?NCvw3L6iXO|5W4&A<) zGpN`Lq<7pOxqw$@C*rPE@u5M3u8R?W?7cm0_UQUd*`fg#MywZd`oV#~*S8yq{BXRX z`gn+&K~S+vctm+${hi!7EmYvXO99?&?=+(VYwLq2t5S!@$o!i9*bHW1!RW>>eJnm=ZE)9vZeRKc#hT)d@SoPu&c(z#NC|^bWXEjO*co+15%2V zLABJB@bG4R3N6F`jWTp8?>7t9UQcX1XOhCFtBoEYu-M_(jeXE5`Nfa^@!@1~kw8^i z>)+GLjolz18%i4hqVk7R=IKQMuuoxX5fkqBn|#nSNB}) zGW}djYaGxS+OuTXFUbpl%EMKUemMS@hJmnfrL;%1BorbOT8@N^L`+Iu1|4e45n%7d zgEryNLG#=W&qfrERz0%mj9v0OhGR41{fd{iI2CPAkZbqoR``fdpSg^>4kADh5~32z zrltf%|Gfsj5MfhosY8aO_?;|F_*qURPHwb$XiMu(V{YsZbbff4iCsF$zVcR3|7ra* zNXnEcK6DH#$qIrKl>{5Ywiz!AAgp;A|166Q!`UOpGUzhZCxWb^TDNlxx|e@mm-~JL z0t5tQ*&sJcZL!z8U#L3@;wX|7OlG%76@lg$*T(khtfd`;;Qn=SBm z1<*M1FT|lP+>H2#-@FLv-&owy5V`I~#o3&tT#cP?u8dHVY%7lsg1_AQYuV#R&A$T_ zDk%fM6ABr$!o5M88Sf81!>kM2{~KW*k=D&YlA~yx8&=;pN?khm6fS|VHpUWzNLlwS z=d{8$mBPNVpkVOH1HiCQ@CtnrZ^ys2@b@K>hYL=1al2c14J9C3(f{3Q`joDX>8m%u z6o57-L*~aClC5UW4DKLl(VXO`ubPKcTnvUuHIjK04IBI{SmT~1A{WLh1(cY)`diz@ zERvEIJ~l1(m-(JO$`T%1SRT1*ybvqXu_XuswO;hml>V5$5ABMmRS0!gIGZO{aNNR% z)`;PR&hoFf&7pbhp%joQH~B&%d#JW}s)JP7=~^xO4CJ#QDaBv^ydQl^0D#^3x={p8 z4gM&69b1Q~BIzMO9^n+nGU;!qpOC=&J_E=5Xw8zD!M@J~TAoo*B#4#pH6=7cjQ4|` zLwLB|*xKeQVyxze)L`5~)4rfgD1{BrEDa?W)Xvl@+*R*RlXzzHa~)HSo5$DPElCa1 zv-6gf;QE%C%Sz3^t#-e!FnQs*2fAKbqNWqY!vc&Oghia!idk~)cQA~CFe{l#BH4~; z?f^phRlAn|tezja)d=0aJA0nowt%tg@mDk^r1v!brv-w#xLIxjTHm^a%iA;`YzTJi zE05bF^`?!Z9uL>l+-BOB?BVyH-uKY@6a{}?NgL54;2C1i`^GLwdt5=5)+o81TCl~e zEVEdChST1i=Cp}C))<4v?)~N_L^!o%t%JndT#G>J*Bi)~#u26dKTp$(o;j3po1#;QL9p8wM+OyI}HeAn(K5#XvaZ(Uy_PD!kdNWC>6g8AJW5nLsipk@EtplVXwoy zW1KF+lh4PDNqa(34tgXd{6O0|H~@J1j9hN1FBdi=$KMfO&b;xU#ItR5$6I(l91l=K zb+WpgA(~AL2;{oVy(c50AWG6ggGCRJ+4GeNAuoL_eG-jP`|h+f;nRbK*P(bwVH0s7 zypV||JfY%XE)oZRfy2C_3kVX7icTv!YP*|O2lBD?8J+++{i+au2jzr~0B}M4F>2A3 z2uIG#7aBHsh3d9*+1{BAMzWEH>#%~xU^3ksi;kKr#&A;2;O+Opc9iY}ywn>?$pxm)oI zRpv`pms^{-4w+`r^@8uNyPM+T&?AdQ`y=$wCf;#@HPU2<#nvOT1LM?E%kL)`{Z&Bt zFMES$`#fWf%YMmvi41)?s0cE&lF?06w))LpnX-=PU(8?x z;0`sgzzdTWcx+7FYJ-cNj7G6FmgU(+CN0EX#zr_ivfcV?aj<95dG?V9hjW2XAHG=c zGa6aA$}f*64F-!ktMf`-{mFU?1JNZ_${K09A@31`gkf6TdPG6Tj9f`Qee_J~t(%O5ZJLT20aF#AIrFLWQdsVNB3!D?_>oiGFL2CT2#ol`f7U| z23rR%RBE<=6w>_<4hQdNL)!<&!PuNVhB^hEn&ifr92gK&rS{d;>K1zd9!q@xKm@hqO)P`WpiHZLT*wK4@#LymmA?+PM38<$!H4FeZg8`jChss6T&?8~}b7!H`u`m~6maP!A2KO(| z!7p@6WTC$^7SMN?Z|1IJIVx8Sg=o(d&~>8I z%4A2yN{fYY-}$DDA)-M^pZ5}(`VgQk6cC!(!Y10NOw8o(DSMuFqqq@m?XGy@9Gtd6 zluq;u7w)5}v%B{iUY}XI%2HeNzN{hLy(au2=1)`5V(U8w9&%Gz_aym`I^X%3r zHl(|f9ld-xv}CR;C7%~`Hrn1EwW;mHNz=A<|2`SbPl2!ihz>>|4qqv7(Q|f`jP5~X z+BW?ojCEWD*UO1F+Gfap-f48-n`GVE-}@alAgwn0hRRy78Inf;sG`E1f+XuaHAhm} zD(>R5*QL3o#DcmdQO$kJHVGh z6UF@)0c<}HWpu--W{15Sz6pEJ*AW2`$0G)|LO5tRrbQ+yItGQ-<{%A?>J%%$-JI7e z7?j9S@Lk50w6m`$9DSN@H*VQ9NUF3@+L2}ZurI)W$mnM?t|E!IZuEiZ!|@g&_q3J& zSz?1u2sWRFf;1NtYjxlcBii~0wHDPc@0O!9Tol~vZi4THK{KImzd}EAAm6{r|9cWo-vsq_@Qw38btvJnUb3;ELd;#7E)y~gUF>b`{ z$Ln8Wm->@f5$(xA!xxYAadUPxQHuyxSbSzCGN@Q7eyFw_vmYRQG`}c~d*KIC zJ4)E_aCoQ=VuPSKT<7?9Y~%*E?_{RvMIpXjpG>T#StWe7~hnZ(|DHH{TNy_Y1B%E0cor7WB-rio@JU?%vLBeylEJVUgUc; z70FC$aNPGhSSM8k#M0@EtMx7+-$9TUVSeIe8`LTc2xGVd&axGZE`RKFrButCGf<%q zbTZt0-OF|*f(t1~lDy##1N_K;s=V*U(WS#st4TO$)EhS><(fIl<-Sg_+hI*}7wjMB z&X+5vscvK26KWxtwyx%?6cj9a0`LYTrIpJ9&hQ**erxO`;In?KVcSQGi3e%1*F4YO zFuhG8i5;Od7PZYVd&l#$A#{DMXp4`)8@PuiY2(Y7y+i1wP4+6X)a-SES(WZ2L-a+eIlL7CA9PR@MYa@tZZQicB-a@-LF;o)wd~KF z=fC^`5MF=(AH#~Tj~`o64?uT3kO;|dE?1jr<@@s(O(k$fnb@1;E0+%fk0IdY0YYNJppY#IMuHbJc`qFfa2`S4*k{|&J1U&2alCZ^A6x5Ym zOh=i|ah&pQl&E#c^CelOe#01&B=B1+h~pYF7z>0{*qYX8bpH(_q{KWI`Q0TJhxPK( zSs8_P6GgyWFU2dBZZ|as?1m9-Ri2BS3Ba#UZ@rFFBk;X1{fVk%z@nxzVu6mZYyj-l zz$a9#jpG)XtAOT=iYf5O0N&-T-ij5Mj4L@8pX zpjE8Tmm9uo_=p+AZLQLUxZhXzn+NVAbg&I}L*OKW3@0Ey&EAOSUl_Wj5x{5WEf>8R zqRa8Y!JZ1Dp?-WateJ*bwf(16fxFaCvq=e= zbyR*(Xw4%3ed`#|a@!I{*<}03U{)6<#p0f2n7>6A9p8%Tz1ud#FKJZ>w4Tvm=AWDM zi6g9_)XD)~5joM_A1(a$Z+ZJ(x1W z8?82cDf&R}v4jdUqBFx}|Ahv)2wzl|rLi8wpmceFl=!e!l4D2$eFZ<`Bo8P>| zQuf@9e%H3mQFo6eYbJ2=b)Oz+t62?^Q*>E?@O0M0xq<%_k1_7oQHnQ(sO{$A>s5{z zd5azq5g9OG2W3=IMcBTzCh(#M-|Wqyj^uh`Dnkt7NDADG?3&`zqi}ZwBZHOvp>$_GAXtE8dR3bq}qQWm$Z+lsYReLRRPP!nJfE{%S=taL=f|?NrR>YzDCwsxGxXhXMZdbg7Tw zM_b&tm_fC<2YntkhtGh_l!s;t$RmRA~u} zno^s2(u1IxU6!D-z-V*-^uwZ?WBRQ19=eVhrV(@1FC?`dL*vO znMl6zrfeT>lvNi99T#H>T7s&Ww1h$^Au+C(0k>D>+O`{|XGU{%0`c6aPKU2=?nKZP z4I&i0B*LUcM>&5x*CO6j+Lh(c6|{mOt7*8Tewb1>J6?7*uZs~#4SuGBBJ*xj0>7JN z%UMbiGBgnjiEa_7y`t_@NTXg}}WvC!e+i4FE=0 z?TmsRv#__PjASHjd1bW%*2_Hi44Vt}}kP7jOg z6TdXX=VkaP0O~3Xy6&h|jmWfs4{GNn;B5+3iq!@*E|Fz9j$)%KrJ&~>^1F+0RH`m@tsK;3lU%qniJuNr=}za#aggED(J?AtA*WBZ zCee26l+nAZv{nstHYmUMb}(+ML8;anb>GO+8S+T#{48rlq>}k~6G* zK!L^s;;XYu4w*~-+#v;+@>dFLYVJ5azIU4Yfu!Zs0dme=P=UZqR2OtuB)nQH&g)V3 zvooaa29iFmLc-0W)Ur+^A96uyYkk1a*2m^!oQ!;juZVk)0=(Ja1C-4U3BqeYrzO?P zRZ-|cdK;oJ8Lp70>k~@2i*Id(cF>L4X*O1{6C!EW>g7y0R0@yOWFKd5_rv9)P|AB2 zr2pXFo(tK_V@h0d^LCIm0d!cBzy2%k-}8ooKySWsX|jS73_;XbhuY|_YMg;OX@=m< zIM6#F*81mD9qODNpia1)!LYK1q*mK#s9px_21rmLlYj!)MlaR6?VQCzq zxX>ydAE=~6W8DlS@AoIx)5{#Xcr7Nu{H>nu=0|qSw7c`5Y%6C@ae_B}JowKbr70LR zMEA0X_BT>Wqp9bNDv+j(3^HTN2PcnFi8|$bV;vU?S4%{hF*t`eQBH0JApXHmv7^fyoQ;31f%Qr~!@(8}H7QD-{$PIjaR$ ziZ)}Cv#dXSI5Gc4*7rcAk=J${UvC4PlA0-HR!i6%IvW_eyiz1CSI&xW{ylYtU8brW zr69TtVl~q8+T~X@j}?WFR$tR?<&Xb9G!dh>RoS)X=xp46>;5n6w4$L}W0T*pKOC1I zB|p2?n+$Z_96?fNOCQ!?xKEJVqkxuTo!^_vX^3pKyLMuApjm$49!ykiTEV7 zl}yiaA)Kid0j!Q=O7A1mpSX$X=QcY8YNExM;(TICH1QI)rrmLmz^H|}6L>BcVu3*m zuc}eU6Y6GPQnw+T8<|=$`QC-^WOcuh?e2H(dALl@;7pR_UqvUfG7V(4=^TF6(X%i% zsk!WRt`|@;jY;e0|M%J6qGjY)_;B3N#cq{~;V7QDf;6kMLdSI04`DrDv#6VQCJb1o zM(e9i)>>yf_Jk!#+=6-i#%4WQoVhm>kIfX$jMQspWa)Ji?)i8_W0F`ky;HB9lk?72 zhYkmi_J;f&`l+vBhzn|HB;5NCE^BET^!fBhFOYm8$%I#b*i>>dH?6GM*lR;iW{CN- zfA;YJGeFG0uCeB^+ZsuxFioRNB_qJvLb?ZtU%&slmc%8_c0X+nhzz)7oeplD^;u#o za}R3JQm31`t6Zz&+9p0T09*3O^^h9Bp#SUbXKjUteLg`%S9SSViGX_Q?0Mlx`ydQ8*gUn(61(2aQtg@?0MO^HyM8akL zH}P$Iy`EIF#Zri-G1Dr!h)5U(vuS8lJ{?k<=-Hr=$F4_}{3?M*T5FYfb{sWZX8bfP zWYLrXmXgsu_Yzj6W-BvNM59X?B70*vg7uUTDR9WJ%krqp7AM&*DB@1&j-4w< zAMi`uRs#2tr=^5G41LB0N>uJ8hZ4 z4TOR5n20+QSig-M_Dh^8YM_(({R3Q$9tRIwu0MW_xyd&EDA0`rQY4EBl8G35j9|ozqSu# z8)GG5(}(kE>yyn9CY3)uHJzkP&m4N05(oqvyM5ZHi=EPaHrYGfq1gT<3lRsRN&(+a zw~xioslG>J252#zJ7}T>(@8||dmFK?$f@RdbgQa>#m|{4#*OBSvB+o7{0pF0`1CQ>4TB2?On#%S!zj9)Uj6_S^iq-du zI3LRST95ITd+XUF6fuX>b{LX+<|^lgyj7QTEOLNX$lwJH`U*Y+biNEATW&DZ+AQu@ zU?MpBtukC&uYO!yiRP*9#KcOj*2MpMR0jL!eTp&ehR1EUpQDUuD%V>-~uYFm&wX&-9#<5oqYhjaS^jt=e=!-c{*VBsdK&;u^pAUpgLA1rj$`i zB65x9gxnf`$8;_?JVoU^*+Uk>d+^zP@&{>s`vfrLX2)+;q_8%uygOEP;Nn5#Zi*Ja z?IbaN50qYlrBYAQ-jE0qH({&*-Is%VXP!0|YI#FUO33AleFOHAoS^Ob9SuY0ar?T@ zg=k4st0JIjw+)yFt#2IjWUmIb8qW+=_T{%C=@wmOLr?63}r``5RwAM-WbyIN}! z60P*|Y}70-cwK%}J>nJ7&i!SuSFi!woy5M#J3Kw3)e=uT=E_>2pNXp6emDxxT)J;rqI918JTEm+W$VQ zF|%V{HVQ(vzT|;~@WL}fB|2?CJEk;IHx5b{qkD!OOL0q!0(uMxlZK-Ypz<$KJv#@j84iM5Hy=`t`Fw6Pu>UVD1DPiY6nG ztI>NwN!E~njL?uNF(F8PBfIv6FUd)lcW2L_Fhw@F0=4OuFo=18^Aj8$Oyb2Ayu4H{~7tNL5i8sqcfyOjRw5t%;Ejnh`CexWzCDzD~9NUI4Xb}b^H`JEy&Pr zhGg3Cp8!$~6Mh}QyXeyV zKTx;JM@U5!ExhxcVd0?iru(2}ais{j+{e`{b1N+?$NdBpa^bcemjtoRyww6Ja0qOV zh!F5WP(P>T9be>SxhgiWt=;{z3>E|2syo0v41_bY!E7G)Np#CnP)q-kl5Y7rU+xUU z^-shmukSn)Gytf2XZ>WEf z+j7=B!Bjr~4f$a|xKgogG#C!^Q-BQhmp%d^%ngYI?PF;NB(Gbjxtuc$BA$#$+CpI< z637P^Om^uy(IA`ioLB_|x}gruH%(5`-F^yY6=K(_u&k z+`qW2d}3%FRm7&-$=<^{G9i3n(J%}X8(=}dQAcJ0zq!7gvnja*!$D1qIyn2{^D=Y4 zMLzejd@AJ~h^%T0#98MU24S}~k&=|4d`Y~b9u1LGYCc_DlFIwS+X#qxTR z^S>s>4#u;ri)J{p(UwLJQCM$%xNpC0cNyT}a ztQrYpjUpIHO*JvQ_a5$)Sjg$yGA>*{iu09g-zcOCg&9iD9W8j;lwHI=q3OIJEYcY6 zEx`lX&+t2m7#0!h#>?afK|)320OF%> z9KXQUlC@`Hd?!JD5tAdM4YJpQkMp%-=z8jykcL+9u7ZTEEl$0Su|}UOJ|_0%${32U z;`AFmkQWx_*4R&vyTn z$dc4z0jL8A?;P`m7+B?J>oP}=Omb0Zxsa@gP(sB8Qca{j<#v>`#<}2-@h^EnH4M;? zr8esYQ-VSP9p?69hBM&L+l54CxBb;$d2rc5n~lGVWFx{uRWSFLg-;GfIP=8}btyo7 zCU3%hij+Ii^2C#isV$J+d=3i^6b}gvA}XmzNo(3Lo}7Z`LJ4+Dz7~;K_Rg~EHaR~# zt3)5MU`K$4>;v9KyTswzvnU@QU&QJmWD7*{_d|!JwM^rcrao50X-fHd0vIWk zkr!^xR;U(}WMR&^{;U>+Tp>{&Tol6J;t=W{@EsixYr{{_DuUJQ6m2%95g z>B7aJi=8x9cG3H$albzU$CF(!=Q-409`J-&Y~4$%kS5ru;Bx}f|))@M@r)T^1JF5vM}PJ$qw8$k9< zQVVyPr)bavT!bY4F7DYUVIgZ^#<0sqG<<*Fzt7we z#-E}b*3MZ67OU41r~-hjt^v+ke--P+jeNS0u3VrEK)j*cfig+%V5z$c;j3rS$A|S; zfL0R^S>&*>77i1J{Z5z4Q0GOEJcbR|p`yRWDzk8lvt!WU94!I%WWB+GI>8P-Q8%Mc& z_{iV1$v&Dg7A}K7Pp`39z}Dr7FNBof(w7;%>m8ZI1MC(m zPYMf6m$3!P{=RUGy5MW0gRK1cjHqnGn{37nGQS37RvH}hi4ZUzy#bdg@_Da+T7q#k zef>nQYl<0&C^YWmuxOt0wJLkr8%m$nv4rZhf|VAw=DPgwxHL{lxyeIIshz8e){I4U zOt=tS5?!A3B{}Vd5f5hT-!kP92QW;G!ZOHseKLQ$2E~M8^mTKkCS(NJfNYqYbE5mw zQ?fY_G9quNCy)?S4uW?~3Z2M9!SuQjjfM!fMbcAGSf&dUi_mQS)_am+8OU(uhJMqo zpcs)F^hX*pDOHfCiCZ9XHyr@vPO#MFcdNqaewtkUps{2yGp+(%-XN|`N~rRHBxlc9 zV1~6$so#tZHEJSR4hD6QV+gdA=kD;G73?jPLpJPY=urjCG}iyWJX*!+2DS!cmytBP zFBeZ_yScR}yn!X+b+Z7BK7gdJD=XU{`xYVA{tNmZgG4hN!LWwZ3OcU1QA+aU+~Azc zz(BqNcuyx7#*U_~0Vwb0v8Up&D`wvU?2`fu$ez*9hzZZx*Z#%j0na^`O&Ldzso`|v zmm^!cEwTcZ%&|ihN^ZB*)eGkAHek(XOyO zJJUI@)4q2Ny`dVH6KZvB^>YmDaB7(u$Fp}0vAx!F$I(>KKR6u>Oe~Lc)i6BI8W8dt z^(~NZHRhuM;^~Im}9Tmm^=3tKXdvn-l+5nn4=W+B+D#GMwgt_)p_GdVnOr07xH}D zW;FT2fcthxE7Eo9FQ7TillSPFW4rk^INT#faQe2BPXNnAUaF;4su^|^q&89GayaQC zYk-KE;3eSNH)1_0I26UuOkmtfhbQ@n-8C|tPlxq2h=-!kuJ&kaTxF^tRqO=Hjml)8 zT7>3zXYxJv$fZWdXltlK`kC4G4ARrqV2V!cwWmy^_7nMP-yu9LRxM_5t1+0g^$rEe zmqXxX9+%kLAMXOkW`mrJu?_&h}@G_ydmHK{_cA~ z++qjDA<63ffe6$McR*Lefj?pl{UDh<)i-U$iiv3JSV?DJ;9v5xUQ9?7j?zQ{VDWMo z1>^A<0g@;~gcqG<=^ zzazfIv?l}=pOq0y&cWre+T;i{7Q4HrIJm@$v6rB#y9>Ws@|s-%x((*z2X*tuS|a4! zpLH_KR?PrIz0do3#{;ZJO5SOuY=33E`bs~L zuXA6d5&s!-A?#3&OJFf1x0`7cwLL9u0UfkNzxUMUAYut4og~0)M^fB4EWWZ2iqaHE zuaU{DU?Nf?e@%E<+PuY6#gyS0c0=3f39QIDruy;=)K{SE+lVHeW2c~Y? z`ZfD_b|D{BgCaTxiW3NE(`bCA$MPQD;Nn_Ff|vIZFX(MFB$qr%Sp0*AH4 zOmyld-Sb4m>}L6PyN}iBQ?rKgOhv!f|1(}J8-7Capo!1<+$%1$D`vri(tK+y(tc2tG}SOjartnxFE-thG9u@A2`y%2IGIZ z5zj0@i#Yu3vKYLN?F$Tcgn45pe3^bTfV$rGC?o=!cOnMQ%kC2s}?eu%1>ChS_~)0O)A;lGf z;Mh_Js3HpSk~5qvljVb-hutbrW*G zt}GDFiun05Qm2?^sBwy;rqT2*LDn2>Aa@GsI6m0LCub-cLn{5TIT{D8@k$$~I7g=% zr3Dv{h`3hhS>Qlf7wNFU&NmXWlzveQrk;W3j4pPrb3q*tLqjppu2^&O}&*FV9Vp~rJD8L3)1Gf z*DV_tpJIW5omFzKBg#^BKw6|iWs5}_J%_FJVB*lCK~R$LhfS_A6emZaJh1#`S$;_? zTMBjsk6!(uy4EXbs;<9naERNms_}Tpu_f-4x7JxIsNB&qzbbg`%7Enk17h-JBbNL5 zRgM;?dh+mZJqx%{5)f@80qm`A+skWR)Wwy1IZ(%R(t^o}UtyTpWAW#~uQnsgtmq^q z#VVoxW`K&pb6!b)KAgEucc#9cnk+igvaTe{F3Fx>*UP;(J*f|0fzNHbW0H`-3BVKb z=j2Bv&$%*sXx^WXmt=@XRDZ_(Fx&}oK3s|o?)e`p)vd_LRf{o-niy4dP8#?Ry{^Ogv*VMr~39S~bq@m-^ z34F+Ipi%`kU)*e&oCRz=l*g~L&F(z#l5tCBxE=R-TkM6d_9N&& zsi!GXG*b93q9%_Io-{(n3y9nz{Tois>ylcwjG<@37|i&U;_sQIn>!k&aysbnj#zOi z;HcbUGP@XWOTTjrsadPnP7OehT;7cvDDQ>qum9f9VoG(IE2ep#t}zOF#MpSThp?Kj zX*<#o@HQ3H!E=gh_&OPe+v$V#8F;xg-K)i%MNV}Mhr=!8aY4YBEAd+R*N{7a+o#Ga zCwSg2@J=JcK^81Hk&Zu`7wu938Fjw1qsJoRhfAb4&ddtpLjpPd&(NnTqF zU}yb!#V_$unB437<+Xd7wyS_Gk%aIlrN*TTg4HGB7Kq{{7}^xXr}KH$nP2cZ;-5C(4Zu`UfEKopMDlE0+f6#9FsglQ#x_kXj)e z_jk#k%}plR^KpMQKx+e13cL}Escf3Ahm=REzw_?fH892y=@EP`P&0=Y0{qw9Ar`?H zvT!3rZw;d2L<73`&jcSkMVj1PBjQBvHAhoUiU14m@FPl=Z?Hl-qned2?jeZt9_fT# zEdsg)=tHzNsslb(df}HTuEu9I;I=$wU!56Wx?VXXwu&X>tyRn~|H@YzKEM_%uVa7P z`r?Ped>^U_92xg#Nm>LUfu{Ehz^}4KxwSQ$i}b&Wj37RrD0FSCHMimo8?NQUdMxwaR9G~oW%hnu&k}4YuO+stM2weVt5l?3Y{HUjJjUGSL7&@tJ@sRHGD_nna{PN_ z7u4Z#yE0wOrlXJ-qAzC0^{hUFL>*%q;vxSUr7iE!Tm_d{%fW7JQPgqY4qY?630K(d z|D+{!dd0NHo_s{mS+%nVz%s$x7sARcH3i+XWfPu%7V)^n-671w4(fy^q zaFGVz8uc;)xBz5_w3~_fybteDPY4>Yq#x2Z=U)OL3hhpB0H>8IOnDfPPWfFNB`2u} zWIj!W$6wfm{Z?U7VrmBsJLd1soc5w!n;&hB#5}D}?2y#*Fpi7_Cb0ce)=e?_khv_z zu-9=T%U%)Ely?hBn3&F58s6!T#q9m^&ig&sV6En7(q7lkLoUZk-N1@(5Q0#@tVi?7 zfAWZp)9vjvRvkVO}C@^jE|qu%q1CY-LD zNnc_D{fnKAt`9gxn%!mul^l@N4|hk|A<)|hzU1V}^4-K^-)AV?AiuXp2hopglT`qA zG>JoKYJAus$dTQjlk&FqafRvZu`7fyaX>YkE&?oEp4)babq<8M6LX=;SXLe}ljI{C z?NDZqY$VvGO4m6|&QC`7(S4RIKMf-oXCUCc82_*F7+{)AffvI&|jg zBb{r}ywC6K-;na^97L|_e2WHNol^&CjxandKYh3$U9%~$B%dA1-;dNPI}6(-n=5HT zi9bFa_esfl)oWCki7@}tB9PG8i%vT3avnCRX6w@#C>c@TL`_#|E&-$ghYvr`hV4)h zPT}osy&~fL)8u{s;8^L!fNd~}*#D+`{moj1UO4%JY0>8Zo+u{c{%U`?0z{#N{P37; zbLtAL7C~B~VI*Hg{m<;8D^X`q>*qt1^#ZWvEsyc0mlzk^l{Xnm%C@@TmV+TC+;4wB zBwa*A)5Esd%4l8ezA(Gv`sNc``cEXEybQ)I{CsJpC$+>2Lz3W6MDTp*31t`wVa&gO z+zU5VYx^~&XtL)ColPQsr7+xe6G2qdIY$50@R8}@muJ;L?*6x2IZHQtcXpn`n_5u{fuvpQ_HAA4KE5`xGVTfVlSgrE7wZ0drO zfN^!Ux{W~DQaQU2riF7Kg#N`T$^d^t!zUs==z?l8;YSwVUeiE4NwJTr!5PCB9ukZj z;h|@vtdWvx@{%xU4ywuGCG;Mg-QK_Np0DY~*rU;@5rl}mW8_uevh>4jt!vxUnCBQPOU}0SoW&8t?B}0t8qc`4aVaPS&wOYv8qmw2C~*E@4Mx|9-jh<+uWOYI?EN4l)IC>{$z= zgr7T?_r5zZfZ+3V0Ga34OT=pXJ&HS6EJ6c@t#j~8Y^2!gpy?;IZD+>(yOb!C%aD$6 zeq=5;F`#c9!DFW}jqa^Y=d2HNz8b&g9ykfk0gGhatBIQfq`HTGaE+1`XJ`jmUCH(S zi^@P#yhEOXluGTzm2s=Cz8HE(qQx%WzDb|leS%GGVQ@?5W{le{8bGLdYkjQX;uXqh zS`}{-RgdQrx``PweL0!8zrvjJLUQ7lv~yVQnEOXyZ$uJi<(4Q{2XJkC@_#cRA854N zOvfF6(@!yNI6mcbd}wHuv~gtE%?Uu42irzr>5~C~+!o@@_u6k1%7y0}iEPoNlJP|_ ze{G9pxWlE|x-Nu1=J5$cPkiR|sDYpNydTW>O+J%YbmqVn=fh>H%}Zs%nN5c_U)Cv+ zR0V}X1e<-|Y15haO?8pZ#uoKXdjN4$-|AaX9wm0{ks%lrhVv>>47upRZ$k8;4EkL6 z-O}cYXVSTV^fLEks>PAy`Lelprucoq6V4L}4B0U_+SRUP5h66f`vN7ZW*njEhTCp! zaJuoc@u<;u#09tdOl8vIShcGp)sOrql;CcMXwegi>$8;aF4((XDX#aI!ahwbr&m{n zy=6&feKNHO3QG;1lXRF~qr3gZE!?xP&{BE(sn@I1Dz`u)=DH){D?QY^wdIl|^G+}$ zS^(+CpK-GNq|fnD2$3pi9~?|Z>|oe-z(zx<_%ptD%2civ$FPozga8|iOCM7fKJPy# zxapOEi^o4?X%#!OJUv*THK|kIfQhv?$UER8%s?uJpx9@@l4)*nipV3PJ@dwEtLyy~#l1z-MkvQhl`? z<-ifJ9-1mB2L7iEd7^mocAh=3EZ_mVTCZKaI;;=W!P@@Cy4O^w96x*KsW#=4;k_hM z={W7LRUidY$dxq_6l;y9rCkJTb)7efYtVzmITo-8J$Ll*m|A9%fh)j|6x=Z0%?F za+k_}FQpxit_5xIJ#F>zqQAo$BQnWJ*8Mvc$8yOU3!9LAdT%5ZKtkGo%$b_X-?v~a zlrb@76pFOxOI(mms7J8Z@%usM^7);&ZJ`@V=@XK!e|mYtt@4WnGlFR14dGlIJIR&8 zN!F?}r^`P^-dWs}(WrTg82OEDvgWQMVAvc&ms;d1Ne$UGr@qv2B79V*L2so5%$Hxj zEOphD_BkgpD%dr-w6@)y4G~j`eY<9aCao z4!@gsT-XIx0HSoRj%tB85H%_X&?v(@WUVUlBtodPhgK&j(t4`h^a6rT0O!n6u3LcJl6f!r+@Yb_i515_d+&&7`Qqv6C&@|WSU#5JcrY2i|Rk{PhTEQ&}vyQzAEgA9W0<+UVm(DyRe z20aW_(LSchqQrhgW;Sd@Lbh?d2|o_oVNHI0N@MO3xwMOJ02cEw&xK|!^uD2eIFhiI_yZ@;wFKb#*nGK(Z3ol{SO`?~RPx{8fyERGn& ziuTCuCpRV$33&IYQDq9@7;ew>=*%iy>7tsr0s$E6)P=~GQ3Qt#ZxF~Hg5tOY6!#FE zFsyz!x@@c_1VqcQb9;4?C#I3@EEh^9MPOyWI89rr(0?PC7VKNIVi1Xq4i2Z-%Fl&M z+g3`#&rqdNb;V3@=L*HsLbR?O##!ss8`HFv2{Zl&V{c?iWI$b8L1ea`0 ze`=F;b44Q%s&4ny$mU~+=dgIa&~N%+v!^fg;zl@h=3cZp0UMRDLE3=qWeZ&!!e-i-NL=%nh-VEHPWN(kAyl4@G?@@7nV+PBMCLsoLG6 zVK$%AMm|Cc9!;)_wJrbIK^Gx z!%ha&h|cRV?repBo?N5;;)nFdW4e5vkqMHU-d5jjg81C^yTjmF_`bo;k~?QYv4769 z!ji06VZJ0toVk*rXD!K(BpXFH2|{b5+Wv%Z<(H%Bps6O_4%X&-Us@eyLo3%LYUUU( z6!df15H8$psRYXut6Nx5>FtryorO$$kHTNLJ(I+U-7TkX?MtrcbUX?{It&#=-Py>s zf7|$fP*MTE9E@SrYRztc4*pY!MZ~s7sIZQjiJNad>FY>eoo+%NehW<-<-#Ozg=OTk z2#q!AQQjpq)QP?}o!uFHQoUhFW9vAHA&6Xt>K17N7j<$Kf+d`4skF5Fa9}O&94jGJ zh0w;`+Al36*4W=6*C(60;~p@9uWdkGOUTFA4lAxR*|OXl@w@ZK=P0?|{sH2JfYhUZ z-4;-o{ceytUnSxx;oRsBnHQHP^=X;sALI}zYmQKB;;)-|AVZw2QD>FKHC4dwLt$cynOdNr{awEs#C~UDP2F{TP><){i~At?l9? z_aeA&9CO3WzGDs~&Mt_Ks=`X6ZX!Vz=#Sl#l@gx%uMU`@o$xH3##m@l*BPUxd_;2%I%o=?fEQef882pwqZ39_B>-G zug)#m*FxMQ!KSRn0lXhm-W$GQKD#+2H8Vjo%CPdlbd`Edgi+F!!0?(xMhLb`8Ixc zs#?E(++pApDy5Q~kdovFI3mz7*#nQ9D*Bj&bo}rC0NyWR10O&Suzj)vX)4(ZGeP4H zXgkB&0->zV=X9wz`(Tq#j6=I_ME=>kLus|y%C0ppRYcki@cBz;Fm*_>O&{&jvpqvg{vqIaU@DYYVYO=5a&LF^)yi2@qVI~Daax0ectrm zXxj;TC&Ic~fJS*BN!;n4Lk;IVcpZ-*HcbS?O~og$N9E^K+EqAFoHvn*0qc=ysqLT4 za#cGIZd~Awk3%6~rG|`WD%ic+o{!#`42)f#+()b<%V9iwf;&GAF@j zg2KcRV>V#2xD^bL!o}t)fJ~MG3d74zI;^5f5fO-S1{}Hy-@q9$d9HV!!He7$%aUI^ zs^v(2$iT>!CCrDZKuZfq7gkf>I$B$46Pcu^v&|-6DwV=R-3f>EE3)zqdImv#VMvCbbC=eH9Xc$eu}Z{j>j>1H+m zB9|-g2MBja*55G}{9VTIstFhcS!9j^fQFmYD~H-jn25LRHfI0=*PDiF?iTqN!{NuF zetHl8th~jo>SF!95pp_GB z!8s`2`C}msUZi>n>42<2KbO?aUv%lKRz6&YsV^`fooOT_^UL3z1ceqU2$cpx!t(V+ zcx{EDZaHJOraX9oJ|mVc26Xudz2?D)uC1MR;@WaJ(X zyRZ$FrT`Vw6!(~h+)4o6zpvd2R~ug^2f%Qw)p$ftNnL>o=)m4^ap0n;Vh9;sVER+( zzQ@sLaTovZd|dB>u~P6@ufe{*$}dKnP-88Hga-@g_GD%iWBqyH9e}kY7b{rcpzzbg z*4Y~~;UM{C*>%u1h1(>NP_0@Np|~?vqqqE(O^1CghS-)AWtZbsm@f1-X+03EaZEwyI4pHiQB^71L$ZYdhB7 z&(Qv~U4*l)M+}(L!Ak>FKm>9*)akqw?TsiI+uIZNpO-{lDSgNlGXRf_p?{)-l9+^>_7+0eA z2AbnW9`nsrbnsAq&IXr-Mk4Eiy*PHS@P;2_3WyJ&s45=mY?V;#NX=6Q$!VGFU=5%# zK7+skv}Dv`hFJ4`F@&>DZ`&vtbPrP=c48@@fYjn9^*$4E>Ol}WIqnp$lCk#|ufhad z5Eq3ADbB(#NvQqoY`fIMSS_JAew#~Te0EHFQB#BKJp_z2(;P zivR$%HF5M#`G=CEJyHEYzq&;)hjz^KTzuGADWa5No5_m36J|_ekt(oi&mtM4wSCX+ zoS7_g`t{b*sLZunG)Syf`~{6~zahcl(ybUt&v3ndJHdPp$@=;lH z*~9@VX(d>cN80I?{IT_gZ*#kb#!yquHx)0TDSA>sRRJ1Qk0Em083tRzNR=&-;i(e( zf}HOl#HmLiw|Xl2ZX$NP&ua{VwH95okl;>4hscI1c&hS+&EqqcbDC!@DyUQ|(lBTa z2-^UR99ZSm(=gwmf85b5r(j+@83GFvtcZMJL|0z&ChT2S|LnS(XO;&6Ua{cwZJj{{ z{`Ku9K3=xlWFFoC(R0>jdn!{8JR|aT2r1bsZ@-7<{~icKE|fr-9&({1z}14(tfgfA zu^eziH5F|dvIMcS`&}+LI!~pC2!a!)6!N_D9XG%p={%49^TF~JWTZsZ0hqNbfcqXwMaN#{P^I3RIa(5-E*)XEoOo(7!4To->Q^Y z5N2~!xJlA@Y6%=mDiL5$^411MJ(C^Rp#<~K_3_k{#w^=+=6P7>?w_laI~BXiBfq_$v{evXEK&wR^driH%h7Uadsmg` zZIG%1f2n_p=KO!aoG0A`O>sQ#+QiYkTo-UeDjC?_EkNG!X zlA*U2@F`DYC$vck%j(Mlh2hlbf~|y(RnA2(h!5K8)V?4Qz<8Y9ZvfHd)U^}_=tg&R z#)Y>~8O(ika!n5vcb&G@=gzFlv4#rGv*v~jOY=_52x^W-Hn3G>5}py!t>tkCc&SIb z!^Qdt*2c3WS3(c%w#PmE*8N!3=gskk=`93wvJd3Pn$jZ@d9G}m7y}J4Y3??`G!uH& zSSWE5`JOJP?B$|v^RnFA#8BrzD*4;Y^u5sF(pS3fJ<$U=(d&^EpwM>iREw{mv#ejb zR6@c-YONbF`IJij7c9{YW#?R_HZ_&EhJ)xLskmpt6=@#1pJPUhGUir9-{|+#{DW9= z3OCT}`78Hzc(LsevkI3T6W(Y;kDc@&v~W^7FqP`5_D^_J z3=+Px>NIyL%zbDl-sIqf=7+82f{y(G$FlHkSz{&F9{CY0zgpSVlQY|+P(D$=_a5*9 z?n)g99l+em=MA^LRx=zhp@VP}mX{)b%m3XOtGUHWViC+)445P;<_@$;|ZbR*5{>`Zgk`AU~k z*;@!8cNS=lv;V*;>~s*~sn8*K`zG#DS9bQDT}+AR9TjDT(I1ss-}wS1+0xlDNlFqu z{cgXhy4L#S1+fKJ(3UrPm-!oHzGwnVxYwF40=ai!F>YFTrP z(HF;+q7Mu`*k^=1$o?E>ibUa}@KUsxq{;!$np^FmGWpqfEHWqRvGh1N4w>N|nbjst zPTn;(f4xXkD6^;L>mKV67puiMjkjlBR7X+uNWgBog+N+okBdh4Bg8a{FelU^?OGb_ zi)&DquK$3BwVK}o9Q%@hTxk}BL1h|>7Ve(-8k@!Mtu{Fkkx(U1a-Yij45c|IV?u7d z5o#fQm6242>k4>s$g>Fy4~l@+JpR72y#7v4$6vMRljL5P;m+gs7+zvB!Yv}#BI4AM z$_t`(gTO~V2aVP03Ux3x7SIdg2T#o6K3_!A6E;?58wuEl(NXpW=9bO%v@s5F@iq1n zKlyu7$uc^@4iDqkBEx1Oji^H&j~Ss@RQBpMNA#p_9z8de8T7owsnrDJcA9~K0nmju zc18$@B6YJ;k|J)M3$mq;h@%8=GEa5HDE5uL*=Q89(09R+Ektw3>`A$$e4_O=+P4G6 zgx37R@AP-J5N9+Rz)h+`*Dx5Y{}|6TVke(Z+zLwBXVYh~_j`L-e_f;TAJLcNtOH*h z2PJZe|488Rh9!$+S9B|C80zH!;H)+aZEF6TatgRUj~#kpZ!?0pJL$*Gi5D4sSD>(a zTEHT{NYWfr_d~j{QjI+<;hMsc7|B7v6hhZSZw%25cVbV{N`1Grd=v*tQtmYzh=Hw2 z@6SzCss%MPzOXsc{>P0tZqWa~SLAS&S7GG`jnu(-(YX-QS_xjt z4Wr^equTH+*b(Ha&$pq9nDJ8VBBr$;{G-6M_}uNJePTdmoVrB zo2JqXkGRc%Q}tceya{kmXlW6b8vFWk1dss+4=nFgtn+^FSm@k-yf{iL8&HK%S_OqF z-Wqfy0r4aIy!!oRE+*4mISM7uVYm$uh$Dj-xFz)s@~WJR>*y9{#b;|w)PRS@nvkS+ z7`ffF+)2!Q^MJL)7%pK3HnSwX%`1tx;q-%TPD9Y30;jQ$YXF%fCr+T%vl#jFs}5YO z`4yW+lJVFbv{8PNKMgxw$p*Y{QjO|xd5V#LrrJ6t+r3eX ziCp~Lck5wEYLXQNj?Dzv@#g3{VKX(fMtI=9ga4r+1gUe8zTpVpY#BXV55^x4X{-+N z>MdRa6Oj>%Ul)V$$(m0`WER0uq0$F3K_4?FY5Fnb{(R)lO)+MPe_79|(m8@83)Lh4 zFRh##sGo}~Nf7OXfhYA9ePH!(!2eX^+iEF?j+=f2(&y=AT!mh+QrOJRwrpZ;FlfMb z8Inw^ptgph7nA6X!iO~6E5%D7qJt~9*ree0Chw$Idg&mG4%#I)ysFkk*9F5Ikm+FT z-JU_RV~od>npJ*%6FdME`8XHU@K0U|&p8MYSt|sD5+Lr(#Fl7c+8@&FNC=q+(k*jYu+exBM7f>d1z_x& z@}tM1+M_gm0c5Ii^n}YA1U{Lu4{Ld+`8Yy$AQ$F1Fm>j{b%0lTce`q?^#{f%s5PNO z@9naByXe3^=NSF-Ssstv*XPv*r2(>Q@%&>xq5Tg*MsjuDr(xf0=mVpR9G#)D+nccd zizp$Ym4`;o5(IGoOF*>0RzSAsF{G;;S>UBHU9oPwo3>1CatMKXthDPA@sT@0eY11L zZKH8%w!KNs68P;NuiT*K}Q-bmOxLdTvyDKX`H3cP>%pmpb^G|EBtwTyDo(w>eA@SlmSRhgJW4*AncC5Ik;HtDlzD!zQ$ne`Q}|EE2xdIps{QaDIOR>o@<3kjsD)PC%2^ z&{~bd4BFZG6bl_K#1@<_W{3p!l{Di4=C{&fQ#eCyUoX}7H^tcRZLJYUZ-X1N~#1P6#ngS65dbR+Gw*fWQ;;qL74GL(&8#E7m5a*(ivAPiLRl$ z_kRj$o6ilU(qj{<>p~$RmcOT;!0ga5`)QM9 zC0TREHJ5pj$c7%<@$Rk=nxA(KEqL%Z?MXW)$|lwd;FoB+aM)>1gehC|5N9KkX@yQb z`h0d2$`-gaxD#0Qx#j69xUnYX)kXKr7%gOv-K?0y*p(TQSEsD_;R#{lL$c3bhF;3r zV5C|-r;LF*vFr2>l^AhpCSPyseTjFS8qXiolW$O)y=9ajGXCSzOcJ-u8fcPsJf_8LsRxb#kJwqG?T4L`}xCsz(NAahXS*HaOriv3GCnCe# zF%YymA>_8x+&nhMIrPl9hIW_!zRt>7u{KHn=nPcfD<45!Jmq%N9^;)kvvyy?_=Y&h zK$TqIKYHp4U2tuw6JSCU%KlqEhUdvz})ekBb z)dB&(+SK?DD(gMhTfCyg|2tzpYWy4)(>`)_1Lf$@1yWm3TbxV{Cb>Tni@wMt2t-?& z*ZM=l<+^bFKzWUHFHIX@Q^|9#pi4fTFA@sWhIgrn#Q(%TT z?ex9fb}@BE^)oYjx^3ovhtZEBRZy8(5PqNp5p-=ZY3WpH$SHEsDM)(wUVbE*xSNsD_I`X6OSH(&N3=C)Fxl5GV_|2mPhAx0 z3^;(=Fiv3TW8j{%X7&ky=0I zSpH>Oy7{p5sRfv93*Bo}vz)#LFCZX;x(wJmi`ZAXe7skzL6J8llCk=bMnY*}XyhH}N5xQRA zfKF#vlZ5YmQxoYR)aib+OhuaD8nbU(=KU|R!!16=HwU?v4S&JJYlt2(#CB;{3N|P| z>h;yH5hdOzo`C{3g|w|YL)%}pV|yZlxI&vnj(j1!W7iY!%sP@KVXM`Pnbth$U!FyOB9 z#82b#SHCNWft4pveimG>@agB%JE=){&$AduZ-OaPW!Z9Uv662x-G1s^wJ%n9vzx=-TU=j|4cU z{{Z$_^#IMR|5lvqH#`MDh7BMFR7UVBn`makPSBZ=Cl!mfDX;2)q?YJWta`UgrK*d_ZZ-%mfYA)&$HGP7zjb8d(=L3W}E4fLx_=R_Lr!J2}^Fc-YM9{a63~hK@EUkwAfY?@pRDP}%BVeU8H zYx4zAVeg_5Zc-+)!3J5H#~nibn}he3WX1w^xi8-fi?Q1{$Oq}bYari@w#>hlkGz1jZjM}_wBcp| zs&%%&`f)%$L=N}MYdcTC2D)G&0DVwoyKYzWfcMbSd2%bV*k3Qw5#*Bl%Wg}e!j)m@ zeoa9l;YHIjVJf{Rx|09mKVoW}gZhR+iM1PFQLg+H$Xtj|(dxVO{M!N1i?+Ra>X#0& z?n52w5#r$VO5gj;vR3#ylOH^_qg~3{c(;d+Cocw-Iyhqha^6%p7D*a5@>iV4 zy1}mk?YV<&tU`V0F1S*MBlPe-Rjsf&QGU}$V@CvSyD-^G(&#m?Rte1r{lG>F%{Ot8 z+@}S<*DK7V` z;0*=%+%V}~kt9mzpRFJlhVP;g4mAj{;9{AFO8=C!} z^oI92-Q2XLb8>r43(-bo+MEPl!cr)~j`<^G%ygcN-o37&#MNJtqW&sU1 zv2dY&h;hyWUOhS(`QjxVt_!f$xmuD6ACRO=FflR0#v%!l*MRW{3gc{@X z?9aqMkl4~P=1(J=98(S^C~Q?`zp%8S=QC%bM1~VF(?gL)RtyOU#aRI#&8;|KorEhR zu05o7;;8TSmuIuy#|oOuK3Jni)1D9~Ha{s{HIR4$l3J@jbS-g3r^){XVy|VisLE5& zMjJlYdcfGubwNcDJB}FnWci?0dWge5HgOp=>pFQhvu|qFI}LUV#G~BE=ylROoiYBP!7M17^XpOy-NSH04rc04(x(T1Nlx&Ig>T~mA%vEpLb4*3`8{`!9ugPR zyC-1HBJBtKA4PRhr*t%*<1El36In5^ULHxyoKH-$Rt8V?HJ6HA=TX?a3%=sU%*T^ zQ8&(fwpfvU zVI4pK!ojtoHizdXQ}#fMxU7#MF|95-37j#_@o~8`8>_BVCe>R|rpxs}nW6%>nMmrY zPU0}zA%%L!bYFF93hR1LK0Q}}q2r4A(lYI)1LtJp#aI$M8>5V}pKe1TP+S__~_ zs|q8m$Rbpr+0%X))Qa>`F0FLgQwn0C)yh&Reoma`^Qa*95NMuQS_z*>E4eKW3fj|s zWeK#buyS}0vjy4jh?^DVDH=_!2#8aUHDcjd_<;nhJ+q^&+>(c*-fp|<>e5FOryxHn zNS5ETU+%u`8gP?_6qWLAj6Bb`Z^dJG9z8zUU7t%lPU;ZplJ{TuHU_BnW&-pvxqRav zN2u)o=j%dA`7aZ;xM`kYZC=)Q2E|hUp6k9w{NfG!wF~+@kJZm(7ILF#rfDHGLsuk3N&sJmyZj?~b!#4C)V+`w28}kGekdgLRQj7A(%2tb zffo>{PK96EZyjB~d(jdX%QrXDY6&3rJpYhG=VI0s5!i#!Q8A)fr`t9S=_rA`I<&%ASTal*5 zCCpr*3&3aW>Up+NfoLaC1^+1a-1}!f^_Hwo2)Mkiw$o>u-+3 z@DyCTI-|#PjNepLYodxLh+$Z|5SyRhd2-}-8Axm#ltX(TBx%9NWzGG?{)Nngd2q`v z@_wOdiWTbmb-2#a*om+}WzKG_l|zjHU7_i-5{25%>>bNpk-(XAL?iri+~HTX>|M#L zGO5y&*dGK(1hq*cRRNRrn=TTwe%~KNnP>j|$Ao>6m5hPk#nv@{wq5^3+so2&8hZl3 z%HbQQh-l4PH`nUKWrdB=^c`I^wU(^LB{>%0~0qN~VVP9^GtjrLFNaB2J-43V; zhjN3ve6g7&;&74Ku&HKr5XLO2xs+G&7<{(xl*l}(+teH!K|001D=vw;QyFFlcHE?g zWXw!4t+59^zG7rCV!pm1#`LWNoH$)Zei4P%61L{)LC(z@r9ruQVt&mJV5I3hE|paz?$c( z%q4lH$@6Bbx0szI(R)xdHisU?AF8Rftj|9#_V}aobS}oxQ1jkU+tueZCu8$LwRHm% zU*W2$alE{DgSTUI7`LxMHPYg$TS=rjX#uA1nBX%meo%;wQh1~**p3YT=h+KycM_;h-()Rb<4SUbw}{F_#4H-Jlj z>60CZeOGuRVwgyO-Z@Lv`+}U~fJ$&+9N-ZV{`=i^`xdx87}(AUC3M^Ga`;8!H*1L4 z^y7qQ2NmBd@+R$gw>zYfn+x#1`OzD|B$5G7q?P5JJ1;-q2x;(iI8>|+D~>PZ?X)TL zdD^hA77{-_T^>m}BgNfkzSm9W=sgALg^hLLi_=iBv2@(UchLJ))K0^GLMOho$eN!< zgZai6CsYs_)DFf=66gwpxK=m)C6|m>9l=TA(+p+`9v%0}Ao+M61mCd+r8rqkp!&xe zuqpN|dqaGPb}O?2urjgWZUE21K+3W_L*`QDG@EgqA(%MCw2pjGQNo}_)HgQHma&8u zkG!Pp6i_X6lu8CcT3D+=+YciPy}u!0mPV@67pN zL%apbKkLPMNxuG9{y^GF{-^}+c+0k5^n$Q@_-J`V1~rX&+H%Z|=xdp14~`F z@e-sYxW>kU&L3fP&&(y4&}(jxX}jM2XI~$&*z8^7`sjtSGV=uxr^L|TaUQpy7!dPA z&M(1>y65?o;`OIGgmN3Ht-K{nY|ocaf5<;})CFU0Q7I3rh|hoO0=SW z8jv9%lIL!cqMy+BH4x(<`6>_@n%?|2a89wg%TJmY8+o*S4S=<#c#Guhimx~^yF^E# zIy#ne`}F6l_`l)Sgeq8EyGSUmls|~+BxdD7Q2@z!zHt?FUSnFI)-3a~c1n^&owu6- z+6@zZyyLxC484~q>7_3=0cVbV2ISF0MS+|F&(%&v4fn#OA2X za;8mfpfvL7sg}Q0fz|GXicr&<6I|9P@FUuTO$dioFopnscHPhe1a`~2LXz!nwGOHp ziDh`nc&k&l7CH#|22Ubl(mYs^IJeOJ%AzVkn^lR~mV*9%xSO_Rk}}Z3Q4QsrB~Q{(bx!j*J~0LtzH zF%++8hX#$$h_4T-EtsU)@4#P-w>EY|ac%M3CJ27NIye;r=#!4c%nx2E0o4a*>rY}| zP>a}R9A+HxxTswdtYl(GsT+uMr)>B(hjVEAi0F!GDrt~mdy8Bj8!oSfA#Dv@?ChbI z9!p2QYGFulDa=(cQ?8RLAdZY7P>-9Jc*;05!`Gj7IUCGWI{D2mGTD-R%k;3=>o?=N zsk=|-&G7YqXTt`(tEDOt7yGfZpj=_Ef;S}afEE~zad&!onOpWh7@e2$Y^z7+wPqgS z&f3-xb*>owJ}(!@;ZsXz)i+hQ(j7_jcYt+_`eQed_?DZDsrjDdW)d;b>#R>yi1p;O zt!fIDWTFa_yBZ!kJ}d+aRY1sn5B^Jc72ipcc)-+7CVE4lHZF-puI3sTsWt5B{bq>L z2NYxIMXsN%=Rl;1e>f_teyoT!L(=^eu4-$PDrvG@?vBDyh;mt-eR6AxRPDeFhahQF zIrWjYgOC|l>^g0$B&g*>{2q#G6mC0l30h(S`*|3a@`G&;)LBM^JD^IQiNfQ@pp-oi z86|_}VCR=}F2h@eNTEz|1A~c#%7Qtp8P}5%897$P%(r=Y;Ah!)QMbZje<~mV=9QEj71yoWBAsM@>M#RAWVNAf=`dYheapi}-;smdYAtN<`Uoq9YRR zWM8X>(p7Q2o&|txFS_y-aNzJ0N~xwPY%KA}ZO?j8N(6E+`x@79!%BwLIga2Xrhwy_&I++&YRZ&U0$<$+7!*?wUF4_k60+e2#m@&CS3Gq2(;p&*%+;X z?GoeLv|R~{OW%we;zH?5@o5u|k6-fNTu64RN3=Uj-;Aa{mq<*S=<>&ZMh7*dyWSC+0diW&FT?i*@aQPk7k_rtY>IK(~0>;?P3SV zA#su6P^~mpb%e9xk%-5m$&n(0hxvv6wrI0als1_b0Y2uE_uH~)|Brz0X zl8&DOR#M4aLyTuv6b0mJ{ISbQq-qa&IC$jTQf{1Q`NGxA>&?+QSZ8ewiNtB&T~dMa zudk%wPBLQ-Supq*pRNeY+LoeRBP6zHF|o$Su*ahl)Ri!|`Mt6}n`Sb-ctONr4TS6~ zn+sz05k!xI&k6YmeSF}9`9`%LFG_RRdAr8MF#`KmF=V_}YQX&{xZql0V2INKziYKc zqQ}qSBNwln96_Bz+MGl6rP9w7VJ-(M+=5Eat{w5N74bo+(}7UGp;YcclP)$h$-=u! z)&3(kOhR)D{onBb%o9dllXII#8EqPYpT;{1dhuI&q)B2cuJE5z!Hv$Q?&|oRU$w1k#AKJLgwIyS5lxdJ}+E36qKrAx-7hM5|)jfJo7G( zO)bT|T4Sc;8gK(4>Q;O*d&d`7x>$~=3kFw>_oIYfVV(ZTht+KJEujR}`)!9ZyDP&1 z`0uM@oe4PA?|&yc4F*KyzOPdL=f;j|pGd>VAsFsVV<-EH27{Vlm<}^7GRAZ#PXVa< zPnI&kl`i{Q7Z7%4sH`+L>E?GlI($*uj1bny>+xmV$24#f)l;y27T6X)%5rC&-DR90&H`m*WBwNfoSj+@ksw@m&|mcmYCQ2Z}KC% z^htqad(FG?lsCKgG8^DOm(c`J4VCFaVsZsa%1YZgoD-@MB;1m}RHDH@VqlEyWR~@n zg<}ts(SIJDn;kI(tBb2};JdgXkF`BEW{V*TPB)H&l5&=a$^e9=a86eHI3Gu7 z%(%9>r}d;0vt+i#Ptirqa)-{2@h~h)7@_h-e)s-REoD5Z(8;rIP3wUz(}2iX)x~>Y zZ{}!5?SQ$ew_iFOMQ%ac>@Ww3R}2<{n$>87*OVBj<`BY|srcH%-V^>tpj;$5n}_a@ zbX*K`J1$uc4Z)61u#?=nr59U7X1yj!9A_w^eD4Ej!BO?o(N-eH3HnT8qy5b5Y_6`w zFPQK(!|IuSUHE(nXX9-S41#pGUX|*&qgQx74x#+x?a#3tgjE(f_k-P;U5{>Ti78OWiWwSgKjKzM z>~LnkU+zQ&MA0T&q=n314v(AY8@$$OefM5W^0}(LPB*ZXlLc$M+q$xsuls9VJXE8) z6h$50PzcZWr#A{G0TQQ$l|Te0vaigYoOGgAyi;Y2NsjdhtRw>`GlTK)`aEmA=Ml5_ z|8bQ4c?U$G8Hx(5Vm+|3cp%sF|EE%D`?%O|8kz|jzP zaSN>7b!8-P@hwZ?oC5;%cb6?jbQGqvx4gZWoyZU^^pz}Wx3T6}BSA?-VIo+{6DBr! zly*6sz;TBC-gg4;?6!`Kg5tq0>F8ViqD14MiLpY%S$TZL#8r$iW*wc< zigCt`W>8eqO)F;+-Z^cF}smDiP948 z4F!e{AQN3^6Gb!x&Wt#m@&Q_TLMbtQEex157%%C-SQZYIlY~^U04l$FFd%`6p{AkD z_9r~RbDh}re|EVTz6xdXlR;BC06$e$J^7g_LkGDX!vi*3DmxS5g7$Rn5_s)gGX0X*8 zaGpx#7}GL9i~2%BcD^ReG+FEwEi2PccgXh1Ze z#GE`_!Mr;~KDbbBpS;!-R2St06J=06z8m8xkfDSXbA(fkVjYnhD$`g2oU``g7X6tQ?4nCgpYOT8V zL&Gxet5${0jDSO&Q>b*+bS-SWxfpA$lVTXwtbd9fvQ2f3Wu@qH=o&W{H}4XS&kq{p zOwbq$4yWv$c_2|Vcvv#_th2+Vb6x=Km7?^!7NJlA@?Ts+SE!DjZ z=lqCo(oMTOyinrl5WHGRo3GHGB>@aZj1vQS-tVd0On;Zy6c6xT?ySz^><|3JQTOeo zu=QKLx3x-czy4HhQ{sVoH?90DQ~2dEx0%;lBAeN8eehk#`Gd@qpQ0bA#jpf!4u5a={o}t%2hJpSKW5ReIxBv*7e4t~IH2+X{B?V+ zP?=-VtTh&p4d66$S`ffJV{C`wE=3=WM?J{vzW& zRA?8B&q1XgM|za`Go)5#icZT%I>*>ic^k`K9Lb6cv!i;V&}HV|IqbjO`L&@EbZ1Bb z!o}weBD}9O1$1We_}nj4W)Gn!F77(rb@!{t4v|(H#R9qMeW=h&e;c+6?@G-b(#%df z5@u~s_wL@{-%n4a9;UAm_dni^{L?En+&zc7{r&LF1gjz&kuNdaNGQ4+ndN%1oZybo zEPPK`(;7jW88Re!RHnE6KmXjpUI|ZRbam0#EwptbfPV+BgDua&PlCy~rB=;49pNxw z0^Xeu6=-8n5oG!X#8+L0df6k}TQrA016Mu)_{(!`W=wM*Y%&E$Zhr=+2QUWW8)CXL z$C74{u{`aii5vVnGE={ScpodGS;ne?cfW%=flvBrXfLdfUOtU&_a8{PAV|TQdPzr~xpObk@j?z8L>ok=xesl}t z*Db@I^sE(5Gc?gN$}Wk!WQvexAH&xhJmSkA12CG`5v&FxHev{9VfTi^^C7*SGQIcqXkaPWC)6V`22`b7SFj4d{Qy@!ryXcnqXcJCuc9 z^)UWYp?wOHJpFH3)_If-kZH1lhHr{lU!o5|?96ggW^7eC0!HM@B>VSWh6a$Oy%QYM zck$Q1xj(3^V9tAERWT>_a>M0Slf_^)6XnW+LX6!|RLi2>D))zEU6C3WWmjT#=^uG6 z=)j$#NQ@>9*T)r*_PESB=xb=Jzzh^_;pq<=u$BA+HC$`)Ds>J-vkhAO`wLF4c=>sD zCHW&Whd9Y84x1!Cenp*3o%7p#K?y6+RO2gj0$m{@SpCK{12tliWvB3*%m#-(5;qHE z59+kp#bL{|)Td!AA{lO`R)?ODLHE1m_s&zb+P|P!?dvm!RQp+#o=XjE(Qq_dBj6Zh zcXaMY(w!HeW>1Jl(*G3E5x+~xc)58#2;K4BAZeDZAsj8gsZ{$k16Pxf6K;RdR|PIe zV8~B}%Vbx`{eTotsHC2HW4p@bn+#3DBT_dq$j3A5+;r=l$7}d78lT{&S+9E3_2VYb zCfNhfw~}0q0kBpVWUZKOP_~wa-j%46sy1Z8i%2aLK#{urDxmSX_kiwm8U(ACC84TN zz`DhAUOW?DwYB?r5xf{7hJOt1;7rvDfr|x$`_2kboeJZLH7~%j4_&OQNqy&nt|ZA? zm(8N>jH?bUY4_QbKPn2Q@CfwAD?ZLZ=G%bMBIm7~ml~5uHjc~?kJq$HiW>d&Fo*QM zeh+U1U$}`sOZUk(h_pt>qc_g`CB}V`HPBH@D*330ZDU7!EOiSwB!SH$$mT$DxlzlTLg`eb@3F=z}_Z1^P!sLG!-MA0HAQs9|zfyy7Z!}InHxFS8t zKhI{GFH#Gg+LsUwD{Lt#GyF|KsTCI$%tzBE7bV{>Eh>WHVewE4mowP1rz}R(?WyNl z;2B?o(m2y@0k?r1h&GY@$y>#9qY?YdLsFdW`5BfoL_)0a_X7Pf!TdowV@#0y1-|Ws z>ID|7QRtoofpLx9zjIhVF21KiW660vp^x)enBmX2;G082%@nDylEj-NBoF#_%R9D< zJ?AB1Yh*dO$BS0*thxd1d7i_BA3i#U=b!Kxw9q&RSHsjGTCbDro1RI3mwwzsTvnCxMeKNRa)QviIN5C|O`Nsn1G9yf7b=WI*K83ehT;<48MdIRmP*6D)k- z9|_kJR}3AshZ@60guqvrF%*yid&J1Gs{W{5z{t{4xai{PP>(EC1_`0%%~^?Xw``BB zS>#xQSBp#=sX6D?GFbmm@){H(tGZ$L$0qt2HROF5;)GWkiVqLfY~%61S?H+h1+@Z!CV`{<~UU|lDkOcr`|POI!vf3*&C;T zU!^Ckml19VSt>)tzB1*2_4UHd(wgOe_cL9IcQotP3Wch^OU4^}=O(Cvx`@r|3~$EK zP6}yjPcIVnXJmU90h6{>Aa*@CW&RwF8x86bBhSZFn<)Dhm8`Sb*+D(gM%5&mszlP^ zvPBHAo)%NIOk%Ldt6VWbm8t*4hlA*L>!`A7Y=E*$kqNrQSdV`(S}t=Y1pD4*qn z5lQ-B47=y7+$BY3!Zz=c&S$snpHPiJ*{rq^&+ETVRp6hU+g*bHn4&&tRF-0s91>oK z&==Uk)&06Pd_vgJgJR7Iuw_1|B2Qpr4%+`<(ewXQ|6qGt1Zu6kWD;zG);cU>Z}ILD z^cqT^!AEIy?9vzse$Z<@kDHJO!xHLeCv4Vd%4F%41(0LFlL-5{T=%vAO_aHI8pqyE zGZExnR*9}AfW%k$FKDi^jLw^!2IW_iJ_hYpFc0@hiZwugVtoN(gD9qS82T3zlV|@7 zRm;0Yz)&^Z<#=biZrv3E^~!4d82(@%5e(nMUzAC-ERAqM<~?v28hLQS?QG}{a~StZ zhW#1sj>JSxno)z+Qfe6-5E`DDvvB-t_(qMi(d2qiCJm9nZFWq-fsu8I%9W^(5V{MK zXb`=HG+Ps-LvSraXx;^Z@v)n{*ih(sKK9(edZyY*-X`dP)lk{?{&W*gg5&GG?4AGe z6TPxVZTh-uLprg#YN)h3*{Q4G2_fY>N70vI=S|tiyq8(yQPizVPz|88&rf?ap?_}He93eM(xzk~8EEhLwS}BzIrd~`XD`eWEBT-9*n%KXEr#9iVLntj*I>0$iCqi0WKnL{U&xb#o9?rZ z;AIC-EZdl;^9$7r%2a%LAucQ`&i&T*?ayF>tTuF3boqFzcJ7=>6fFFm@yB+-ng^y1 z7)C_0>nSffQOvd-+Xz5F7$0%XhkJz0I*CBaZNwd_zw zY4OVAqN4nYVC(%vcN%wl=8?wMPuBM5tp=vaHDJTnu60?gMSv$}7E|8zt&TKrdEl`z zyyJUfpnj(80+<7m18KCve~Zf3r>TPzO?=O)Guw)7^v$dbQulXmV%>D!-)V%a?l?4h z5r_DWSV*-YAGmH*q|kac+{~gKn>%cC%+z-DD_39l(JSl-agCos4`mGmS`oVl^<pCbbe-<-py3a8?!RnARCn4aJq>RLC)1HSSd&OO{$Frp}F_Wq4@e4Eu`T(8~}} z7gfP+2^SYpu%H*fYXyqi2}~Nb6z{7O&CU+Q7s&d(4Y$@85?ZesM5%;@P9by&?X~8F z5@sS7 zD=%`4NL5_Zz7#=9=+{fW8S|wYpm^SCVY1HcW*D=w_k%{HapoE*DvIywMm7*fN`0v| zJRcdXIMEx!!X|Ff4E088K_(1zCXnDFsy zouiLQ-Z1ne`A93mg~tI~bKX~=GV}2Bhv&P%{=hom8(+0reO}lRWgd?Eef7D81cgIj zTE1S*Byiv}w!FA5VRyP}tLLP%`FtRCsF-#(FvXS`YvvX@BJ_#U|xQJ~fPDRJNn95&QdTz2a^_2Z35le@3k~XDZdN7lv zQZW<)cvpY|eAohob_qNYHd2YwwZ)&|5K)j-^U#jg5Byfu z-XgncW3MSw-y#$rshWtN33-W-mC%F5pq9UPg^hKv#r+wdQvtV)S}lY$B|4_&`>Dc@ zJ(=cHc8&z;I;;f?@PX4@&-4u|Wt_ z?YW6@Dx+owB8~q6r4a+JXeZMrtiOeSwWk1-L^!Iun?W})!w^l*pH0)X9TX1_wRkMpDHR4ys%m6?>>+zcU^EP0f5E&vV*p-E_Cc zX+?Z}I_8Br^ZpqX$U0K@!lMkV*0Q>{==;HD%|8}_zh(!rL92#dJe;CYuu#d}#degy z(4Qvwxn{b#nt1d>B->tl9+%&o_kOxc4U89{%%!3mYwi#6=WXYRIC?rAcTOzFrbAT!!jAbN`{n3X*84H@=TUQ-e)&0Cza7 z%+*dYCLgsmCX+;Kn;c^Wxh2KcnuM*~#8S0BR+ydPMP6f~A5~8wDF!?^Giffkk?*w7 z=-|mpz$JUch&iu#7N>%JIEi;Gd^}&XyW;BS1yPxI&+r6pylGm|I^glWtsu~^iBO&w z^4!T=7(j8495YItGn!nGqm6W1`1K)wk6#UDj=9AYVDJl(c1(bxSe|!%aBm(G2H}M< z;gqM2;kQHW&Z`g@hB@*mOLga8TcC*_NMFB-*Y2-x@T29*7}!=h?gnuaC(;#1IHk6@ zwPo6)Fz?1QWDc}C4rYx=M*&6RpoM#nZZ|H32wh@6{Tu8>DTmH#r>;3G&mm+r7|F_v z+I`mBJkv64kp2FKL}BOU^wB@Yr2Z|ta`fbxf}x-gX6`f8r+N@ zqFSdA+}u4D_+e*JP)%RAHQEc!sZcVq80wG|N$M6he;$3iqOnMU`f$$&nxI57B6eH( zy&awUc}|riN{`><-w)<_K%s_Y{?K&AfL$N;S$Pb%hPC+c>+F7tE72VwJ;3L?+b0k= zE=&R9u+^y3{&*JfH_r?zywhL8749%#P$yMEc=exM9>>)ZkoD*qKOL0#LJ%(+Fa2_& zv)aT~;OtSbPaj-e92t>+b-KF+!CH&Bz|MIQwtUHz1v@qrJ+}RdlFi5DFtm1M_PHYw z)`#r?<*LGIxBRhjUV{OX|8f9>*sI#FU0fMiF9~y$>(UiemoU*V_$$-4fTW{oy1R5e zYGj-G=AWtEOrZnzJ*9t`K6k3{Jr@kQz{2VbH{}~TBg4jBa*!L^JrCxV3cck3134d? zJ}e>eM*YAH9u=8t!j^RbTS73-28oS31L&>@su zbl2gMF?}ElAHhA5eex3KVF6ae`B_Dry1uBPfck14=&gi9doA)$1ZdYSL0SM!ppsAl zJi;w!fg3aRL9AryxG32e~HA<>a3`?uDnD~c7ZXaRxZ|t|=J0I5kfxT$3i8;Cb zSAxr#O$_tuh8tp{9)IkbAtp1QN?8tD{L+QgRC1ico*wqh_}9GHsx>LIB$Yu^KQgqH ziGQ3Yiipn6g-Zf9YMaB!qk{PEtWP>Bh%Sij#C;>oNmxNmoL!|aCPyN}_9bpRnc$3j zfQtEkH@T(5`I(dTMT>@IyxSm)QeCjZGNuZ_`|vOJ+}j`LcWSl76hk{5161?>evHT- z*hvB1R|$PmU3<%XL>rw$D0>Ad-?ueGGikoXdc4N~Ue6UP$YZ?=&9)*H>iUASi^#rNf=Ul&TxA z=mO8qHnBV^(p*rO+f=}%PP^s`|Rk?S!LKc zECvQf$cdW0mk7Y$$*BfzTy)d8s2fq$K!U)%D#QZj=Vhk=NC(JncHg)*qvlEZij8nO zf-XOp^xCzeErc-B^(|iqXtwAEEmu(!A_ZrcBpoS%Q`F>kX*Q;NLN>ncK0Htw1v5Ag z0MLP4-oLLy4`b2`ELNh|=eWlB6Vv_JW+%9EV9Hp`s5Kr7?Wc#xZ9T12c=LFrW1`_@ zF^v%WFgMe9hDhlCfVKv7x2vI1NkQ1vevZ4N&I(}he(9J2zS4N`sz9t`g|)J>Z=%C>_-4Oo#gym!%pg@mIN5hB&E$_3SI!3eu8z^FZJSqYi_Wb%ZK|} zz2;5Vq^sjrcHfGucVQt6fC=2RV>REEHy-hKMw4YZ`nlEI3TcG!af|?Bi{wKRZ(J^n zgS@w>PYg=#ko3c3iLoT@*ilbU4)R5AZn=2y>cD_uLH8smCHL^(Gz51U8nh)WsqNYX zTYut|S{>7A0Qq}p$6YN8Fu*o~txF;_Khu(}^g_7jI{X*#;tb!QL^(vOBS`X5mck)w z{{J##WHTmHfS|7QwSoB2%h^}MK0g?uxVO4sd*dll6*yCq^n5}2NZx2jkuIEU<3J4* z;p9nMKi7e1BVSP%P2sCk3K_s?$*We@@7FsQ)G<`ZR&17;u$IC}gg25Mw_=G@eug)S zayVsTzXE!{osuOpU^v^w6~zNmk8wzRdM?E3BS$HY7j7S>7`#C4y!w_WJ@$5sEIb>$ zH3J~BSW?Z-D!PZ31GW0PRaeZQ&S1HSu5ne#oJxkwZDbdNsf4W%KX5Hd((&wMKsjtr zOut1fg{;G`K#50Xld;{d5-yu%&pQVI(TH}HQ25)To6>+ug7CJFPdLX z^8GVpmxE@0kan5_nh7UH(YUp)=J~0bYtHXL+rFS7!TEvB3gEb;0_o?^|dg!QTCECoZb$CPKAGF$n-O7h>e-+Kn=HHTlO@i3Q=U5uKA*a$+yNZ@ia zasu9nbmg2$=!o^IJjS`>t+#F5jCprsE%o}iy&`A58+2GOR9-lSMzF#bE3H?ZnUhTd zVHS%XP-@|G@q>`V2O;xYbZ(d}E@dl%`A!&mn7dFWW~amfS)zn2Vt)kceF3qK?XuMx#E` z2(D&j19Q0M&h4n=n}vV>BM3Tk)=jrP1G+OSi9KNpPAFb3{bg(i#!7B8E-|pT6AgP! z<|FG`>(T~Rpnf34OrHQ6JMmcbBi|junFN6{;zlUi@zS-3`Un`YT28BJDBIJDn7-j_ z39nrz#uGZ|@8(X6#WP;q>S>M@NkFsODcpS}{qwouQxlzfo|5#2!=+IYw^#oGuetWz z%mujC$`PRA`Mk}y?&K9l;e9}-G@k)QxcZl-Z?+>xk{})em))LPfUM*v!!i*XHw|To zDmb>b#dHCYrk=-;$UMKldq8+0{`SF)FhyXDy;A~QJ+q8%8f64=PvDaN*%(_m*(YBMf`N+m|~gb4^C;` zGTentdXz%k6!MUH#Jx(gW6@(burg*0Q1~=UJSoj5Bh)Ozy|Tbz5K)n>SrGovASn-u zkHfwoa1X=~zP3Vb0QP6-iSq2|EW)viX&=&xMdvI}TZs*>MA?MT0} zwb8M%CW;;*4DEV46iP)x%h6pcE+rl(zHUxUpJ@yNF$Lc;Xc)ia3B{b$d)Y{C>FB_d zbn>Oj{mkK~Q$SvUX5@=Z>|}$VrpPMt_<4KIhFLRAW!EGhE~?f0L$jd(JwU?0eV@HI zn*`h|rMkC!vBt=`KW0ZHXO}ZRf^`qHT!J{nU!^l$ zP*mKxkSzV&jv?SN2e@3h=iJ6D7Yzl=@fqHXbxE?m{s5+`SB4zDU4ei#8;g(pvLCX5 zAx$>lU|ZRUD|DB8+oo4pr8zkkc&bbua+qCYj=zA;hybnTTybpX2o9J}P`sM^dT?)H z49I=wFsU~U+$(Vwku4}oKZrJ^69 zx!^FF*urD-S?&T28S?no_yF)gSZ#{nO6UL$8(5+0VAyF9+7PQ;^IK)Eh?%4&v@kc z2uktn@-4IGME?8D*|$X-c3i-v23C;l$Tt)MPHR#=*uNEuEQSc?Y&;d~JY;ThkSXzb zuR^3CmCEC0eYtk9GC;9Mi*k*_d_LgZ3h!y>g1S3;={GslUJw!wz1GlQ!(vD$8#hMK z*R1ZDlW*=}hp^cDj&!|CVrU5j9h|gP`eF187s%>=jl-eW2CSJ#V--YSwb%gY0QU+z zDBu2%QIavLhDR4ikutH(iS=&kNSVf~5OQ6$coPH$GuyC})L zEgaI{!3`I=8DL0kQXmBv@#D67+c!s!PYaDJ{1cP~uKnR;FieuxqlADnN)@s=PwU-+oW}cNvp&v_Je^RQgxfu7| zly%{XAU9L}1#dlG6KZyPWk04z@7i+Sq10E z1Z-;`&EDACi>{w=p#|qPz*;NOM2xt{9ci{6z9ML8Ln3sc32aqqCMZQQGA??yZa#51`U4YxQQLN0 zQv@W3w6bM`=wBhRxxrGNe>>d$X{(8(JGqMCPpG3UUV>xYyW5qa8(GFKX=Gwm(lN7O?*vato|N^=TL? zgS(N&xp#&IreF0iF`=zh3bTLE7gDMULcN2F&?I^OoO|9(eQQ-eRuQ<7LC|rg^k4lq z{BabcgXXLKEz%8&pYi)RzJ_i>s2|>QXA9T&$$)bkSgx_ubY|&dQre#JuMiL<}{CX=m+(xA-;NxjV3|MQZ zk>C?*(lUyT6b**M)3)4IvTRJ9msTKX$=gMr#*ZL!W@(n7qEw_EDT!zdQEgzsgVENr zQ}EYxr1q5aNoVn_QvbFSTYkSSvN%Vu=r z9lvyIIM>(pGQa734+@5s5my#!m!THv*U8$wAin#r({<+{#WIgm(b45 z>)eBZR*2t%ug-T4jiJq3;YK}U)}~Lc+68D z2+T3iydR@r3l#cXj?8AC_{E~} z4*N6M)9tPa$oaTEZ59{<3rw0YD+MUHnTeZ0ZISP@%M-7pH()j+L9*A+F96^mFOSgK zf{LXB3n7F6qsOKeRfjc9?i!A}9aG_@3>nfuka)>MG`A_|_a(;N78YRRKI?jXQ1;YV z&l!`(F_L`|preP`v}lCg{gJbE){V87j17TX$=CFLmms1EhHs?;LE)};+4kHCQRF!{ zKV|17ib&M$Oh7#^Rtlk}a^}>k#{`#KLx7)l^VIxppJx&10EpY!^OB(x-~tEUW79m& z%IagtrjyNf2EfWfhVg)_mG$M^%o8+P`H4+*RD#tPN?f*Gwq8en(0c+d_Q04l88vN1 zq)Au9Wzp^9Y{ZPLx-ofDb)h||#7jjAcH%=D^TB#NrCm32WEC+5h$jFFmOXTVGvolp zrs*wC>X-rbf*c|zy^sPg4NiInrgT9#6n(4-YH?6C=o_hLLcJ;N$d`?%-I=LV*wa@$ zE}_p=Bn6Tj?taE*(b7=tiUypA{fkSE5z-PJ`^$)~6rnK1AIzV_@-*0=%0i0x%|yp= zC$*NFO*pMwOhadlUj$>W&VEauH-V!oEkB}AkkU}v4{-X0Z{DL%3%Z9?89NlPE5i{f z2^IyTp9%7ek>m%jq-X~QPqdS=e*0R;XL~00Jeo0fW+!4DVo_F? zfU?nB zt08(r#tq5}_x8}(tO`2ppgQm)oj0@jL2Ly|`wAK>GQ0)4cdt=DVvCICwG)lygy^amj@eqpkd4rnd5eULL&>P?;_ z@pl0vLb}*yPO07ro%5%U1p;$&(M&4wnW|~UYMst;maRqS*YY6)?D02#NP61ij)HOH z@~U9$?(eFJa$&3$uGqX84JQv2TCiRXk^{^Xw$|Qk6v?InoRP;ccw+K$SKZ}!&k+vE z8U!vcD9%_4y;f^O57JgZ*BlnBJYUkzIe8TUg8t>Dtk2Z2ckL*_S9S{$_qZv9kI<<) zq#|RV(&~ng$IG^=rVgb}nRs!z!LT9?97q2IcD{@9UlANIMyPSEIKqX~g9&J=ayyQ4 z(v`N|zbc*O)9InG#zeHSFht_yjmPoYk|BS6inAMAH9wu{{t*}AfG?i)L|;Q$4<8JRJ&#~D3u`rT%5?LnclnL6@z|~JKBuQh zH8vg5@_y4NdqBW7{&{!yDgbUao>PdN;f-FO-Lq5Gf3(yRJmIh-H}t_)I#1(zPk$r zM6QZ7a`g<3u0ocz8SYG>Vb+vE)xb(w+0)49qx+DmuIsaxsHZGxFr1s3pU+;w*^gM~ z+3}8ExFM-?O47>-6+0WwHdDw@9+7L9du{va=I|i&Xp9auLFcjs5d%`15>03`ept!F z|AK0CziZ6)7%?3(GTGIazZHaZUpx`_w!wUHw)&9(-Ie;Av@>x2A&M4r^6mt1;rfn5 z7eUEQFOAo^SGSwh`?=TIZ8^v*fP7)yVgfLQ1rDg5Ad2`rKsXPct*gkJh8>+15}GN*fn~GQQ-7$ z{IA`~=`T@vw-vTW)V?WFjr+`jqX02B+=UAQlep*kE?KYv(FZf7F&|4>Tk zTAj|=u}RXq*yfEQ@3L=!wI)|Gs6R9K>tL1NLK;*|-Z91u`; zO%uq4j3%589h@a$Yt8d(G1bzcDQe!IvQ@d@?zOv_X-}AJ8_0QfrPq%ju!SGl``pfr z%Vo4yKDFzomcUVkNo(1GFG){FYnvEPghain?vc~z^&{QvRsUF&zA8+f04DjJ;afY; zz1C;&bqtFmi_40RJa}91c3sCXMo!`ln<- zWIewQzCXT@ZiLB>aU&`oIo~|Y3r7NGK57HMWi_K|G!h;y zpmK%E!=j9a(97RDt*42}lj5D66b~7^&w@E|QO+*vqxlp#3ODjuV<^>LTJ0<6>g7XLRhsLr{AZ$cAx0yA82HJj9vOd!UjshHEX zriRfU3rW&eD-)FKbxWKzcst{6g6Y4#voLcC*tUoYapEnk%lXA?5AYLQLc-&wJK3;H zE(ApjoPHdMBAJ-yGv|P%TStHp5{wDKVfDcds{QrUaF)`U&M{2Q(!-Vx<1aHM|cx9=iF?mCsoo*9JP zRc^v!w=de!`!JV0gGG6%S)y>K$8BNZS!Z9#Yn~n{%kt@58a%3f2N}pYN(gZhO_>&* z8?WPA&2rJ7>n)a0l9K%he3u4z2=nTf+hic*uT})+pzWJqJsvj8FzXDC3e+8}6%wR> zjh&@Z)nl7Hu(3`bimBM&>(m)-XDLk_frUyPZ14PH`G3o9Ov+&lcU)LWtV2ideN<>_ zE+RYrB!G%~18-yElLLQc&h1_YNZnz7waUkfrSuYC_axup^jZ=Ap7U{6{0u)lP#5Fp zrIMMu+tBc#i}odwh}6Aeqb_}_J0Af~kJ5DSJ}~BRa{yF7B zD3ApwIoPT~Ad`Yt=wznrkjrFp-|;U`Ry)qqXE-$)Va^Fck$wRma5~x}-Y1e>3FmvR z=^%_tvA7r-L-UZb5}V5exl`KYyI;rH{We%c>I0GXIaoxdr`W2<+5eFjk3lOE=Kk29 zB3I^5T|>(orlU7$X?6DL#~#TMiNkpfHC`KbGm#4wOnZE*f)fN8tdOH4nw)?r2}rdd zig+Z9wA=$~u;M@Qv?d#cJT08e&Zj3JQaqQc@enr{eCt-MiZIj9uQPuV1}CF4qBU$R zcL`G$vBk%Qu_yoao7fw)XPEV{GKv@@2qSiHb@O$t1~KKnjJ#a(YB})=j2~I}v&tO$ z#Za5T%^pEd9#BxtNc;`=NCZ=rEyrWG-=>@cQMrhi(U-?O*O2FkiBjN*6spy3c6e`k??e+N z&yp%RfEJ4|)ilXSEbus#Yk|=+gu{$!LvJ*gqwSt^)f~FIBA$K;r&* z7fI1lnV@=ZI`PRi&03t@B?;`3zJAeG@ZW33F{^{dsU7KG*r-BRXuZ3Y622#Z693{g zZ#vtB0wa6gQ~oWO=#b}q`N%cx|8J@#Aq%X|txo-||6}$u!lVCEmvuuIukQ+Ly4iOF zsjC3*tZ7Nl?vuHPO2WuTp~}VF#c&5o0KeV?f`f#){3nH>u0yV`ihGj6NwEuMR6N@@ zO6RDph3~*D*sL@62I8wFE{5&9#R;toS92pfhXJ$6m-ny1bD`Dj6)x~j!CzXYZhB&S z_W8++hl@O4lIqSAb&JM39~k7Vcy>gAP2}$@u0(CVrxVnqXk3B|dF)=h>q)LTILpDu z-y+|f9T_pd{S!05VZy~vsU!@^*G|_5#Ovq|=P?e^)q#d!j{ ze}W$#41rQq+F!ts{D|jP1&}8y1DgJaR4*KZra(yG;0`=7E^E$WgBK>ERk;}g)jLc&_f$pVL{O@6 zyz9V?;!H0MfS#Op74siy+}-?SZMGf9+Tb{SAhDhUoKFz~M+oQg5f-9#OS#YWbU8RV zWEF7Waexa3A#@wAqLW6CCKmf0ru zlXDN+`QhNAyZlmXV%mA~#kM%cgh@vX;k?nr zH@5l&X`-_HhPI2PM)Ew=uVJfJ!C?VtQ1u@cDK3KzC{t!_!Fb>;NI}_>5ny0JU0z08 z_eOH4nE>^k`Js#9E7ke*+}`ycLUi<@vTrJarRlazS|e}Zn*HnPW4W@y8ecLSRG3Dd zSBY+Oz+v(kDHgEt#rQZa9k|t|dUs;08ACM+o+em=r`Y#L<+ht1Vj(B*Wf|jkXmCU= zn15=4clTlEY^7MfWFl}9l9ZIpWZ?oR;wo(KU-B^3T#1R%))VZMjh(?6OA#!c%iI&T z=pP&^|A2(l+)+!#3s|u(C8c;ns76;}wGR-ifQ0xwg`^y9hDKH; z$fj{zh9F+_PfNwS-!lMsO^A%7|2meAh|zuVdHHH98jB2O;w+VbTXk;s)AhFD3WA8bh^g7 z@mt@>vJSw3g!7!Ei_>Jiwx?whrtUW>EziHTW!8E<3tzNZR-$_yHL8oaz$@#|ml7h* z1a10eWQm34rg<#@@h$sKiizV0iZn@@&Js&DlLxslCi4lvn-RsRY-}8QL~jUgcX}4~ zD+KiyMq!8$BogWQx+~eM+4i2_WE3`XAxq3!8E92^AUhA^`bn#a;=t=`uUa&(jlhym zWJKQ?egA>;91o%t$>+5|?;*fmI8fI}iFEVnKCmwvd7I~x1rWm@?O=+ODj$~TFgrK% zaHmig3S_9G>K9~ssiAw~rv4|*Q=*jFCwW9(RQlXF2E>_1`g+b&zk3Lj(a?R~Vd zr!4aIsuGxoUJ+IM^F*0*aO*#N zI~6!=R&9%y<^Rhc3|iy+O^Od{~?*gW(LfB#!Kq6pvWHP5`w31OnX-0CiSizE=V9@&r3D=?`c6J59cx*#rjpL;wZVXA&!PSM z8t@QDeV(!NPeXY&d-bguPf{Jz5|1YS{y!h%5UP}TgY#%f?th>VEfL9nuGZ*F`F}|2 zS|UD-kiINai#qahM>Rw>gr>To2H`Qm*E^FePeJY7uqMz&AKkZRp5uOrq)21<{0n{JH5}6 zLEbO2A0$7#;wHVG=S!jB){Zd4ktcG#NXLI0m?tB)Qgw)-RmNeY6ITGT#f3`TaF3<7 z_3K()Y{A*t|AOw|i`!9osA;^tgV}*c#$b-5U%#|`)uE5SdgL4-rz!I54KjcPK2>SB z4aC9rPDIi3trB%DLgHNr_)Ir@ncVRYF|XMNSK&zLG+X^IDg5%^7<$H40(@0AskTFI zEB@UA_imRORiEp_2K<#_b=jj@#mui)Ct1@*%(n&xB?_|nJi?2O{D3$T&`o+wM6e;^ zLXvtU>F1RKA{hyacs3Z@cYY@cONZV6^;OwvR~qpOv_Rl24YMq;zSF5@DstHPA6jMS zS4ec%py6{!AKP!57f+6)AkNCsovW2O&0@fG{d&MlB$31smwo`r5eBEA=bs$lRY2zs zC~wtaRuB16Gd6HR@x)QEPl{?eyNecq3nqU@Z89o?tM$i)fqKr29=?!N<5I22bMeug z(O+%YGiUVP{}jrxsD%{GeBrK6{WQrrVTT)5Tk$<*XIWWQ1;<^hEWJw|$Al+PKhpBA z>_o|}SvxsSr`W#U*>bMSUu{XbHa$X1tX)k4u5=m&CC|Xy<#y z*MTX;B}8qUv$DduC(JOqqEbkoO--pTXV?UodESZve4h1-3LAk?%u4SB<-3T;V(bSR zq*|csT#$UvK5b#DZJm*_V56fN-D5o@C|D@kI|!UF$Z>>Ew3k7<0CGXv4Z50jPTCRIetu*_TPJ9i z%dzE^?&buMVvcrR8x^Y;Z!BQF11OT|=QZNGH$7J2d3BVkm)wpv(l`LKGDel`>as3L zW9KD30DzOPzCw@vasMUCnT`>%;s(}&*JDQSBx0%$$+0rtxJ_5D;?2&1=`Woj;L(kaS8==u|lYm=k#AY^uPvr0+24cbh=19EOBSSY$S(fW+WB zhCH`jvvv2sm};hMek+2_3S8QUyy0%kn{C>d8CU5vg+i-rQ?mK}^$!PnF)v7tF@l)G zi(brUxTnmR)d!CZ`0^q&x@-{|-#z;yY#hvzm_cTyxHMU~BP!?z^V4pp{PWO@w91oh z+4Vcxz0<{uKb3FS1Hn^NLjDmtQm0=DDKuKc*Tu_TBFtX)ryvoEB_05+8&vks!ptH*Nx}+z`vQ06$qN(Y$f2*1j5Rw zs}<1N>-MU<&<=M6;7dn+v%g)^72~^sdBYcwS$*y!x1dmHkKuZq*s;YvpVME#-+5$C zlpw?>^atK6ZCV18zIdN7ttWJL^s(k^jxcHu=Pn0DyEVm5VE>(=Pe6ypFHS#Yo)rrt zyW`oY>@^7C$T!Ehs%txSi6@0h1yRhW_evB0gKD$S_irOqDO(xbxF~EtV-~8p@cN*w zM*;qeD5kVc0DU(3iQ()#PH@({uPA@OD-7hT%RJsLSHv;Cs|zVOPAJXgsR@5N81w3= zoVrhldVHqZ5T@kFWTp36ioH|?UJN}A*QHl(Bg+Hmg0bg@fy0%-T|0UhUgd23rx&H3 zct%E!{}kJ$cZVDxdw8s?oXSbJ7z+krASF^K$>mL$$%B#XbosgKHhmb+&RuJP-YlvH zGTy-9My0q1a|4U-z2KQyHVR>k)hdW2g3pPre)Zw8msD4`LW$-}2Xf=uWnReVBYDAG zUrL2KC5^G=<&XswVqphj>Ch>GX{OP2!Bkk|*$5s`rq9(624}8+a201bGd9qHaQaCy zi}2{rU_RKiF3V0q+1wTDnb1Eocp+T8%P!J=qhY1J=+8M>yH#^X}EAj=hmlBv6{;vCnG_IxOu) z(f^)wK&?cF!)s%7h@A=Tebyh(hpWELDu6CnO83t#9R!>ySTbQvD=rUW77^voU6Tvr z#)s5e37L^E2{^NEkkxfKi2JIsUlxHuJ;9i+JLZKWlpbEn^M zIaR$eGVlwC@YpW;|JD(PkkSD|m-^%F_9NbC>BAB{mHHS~CSJO7G^Lg7t(nUD&cGLYVUY)9*ZpWT@@)+9^C zd8i_=DOgGf<$XpOK}Y$ARVLgbsg?8f5)&!)6-0u-NoE7womQ64N^4>mgUziO~)O z(x55IFtkz<*15Y#8FjGdv7kKJ7=8)k|M;zZ{B&;J`E((J{=X}lewwn8eY(og-{GGc#Ii2zusCU&`kzJoJ@VCt#YvUN%yDX zk0wYP;XR2Exj|U@?_X~Zi+bi?$!BmOHK@8C$HRp?-fSSEc;Wyez9Z>?T-F_k;TDj8 z4U|?f!!y{22S!I0A-!}BoZ#;G-qgV6H9{ zdLejklA0q5H3rXlW&VnIvz+&$J>pPnV+h#(Y%TJu)C2QuMbxFxNbi@$JPqP4kmuW# zk-GS5I0u2G-v}!nbeX`JkVeml3?WAMKs+yk0;cKQypSGtfh-yc?jd;(x*f&G4{lRs z5fF|OTU5rQllRhpv?R92^LtthyjQ5|An;@;u9342Z3EY?2+{snua$^4{#W)u1b1on zmMc#I8^B|wyV^Qh&%jsea*x*mup2AC`P`1s=5xLvbdM;ZS>9W?Ypg_ik$4U90tJ#%H~2X$c? z_z<*#u({6?jwT07d?Skf5_>-3AsFghgvpd!>FZ34j=?$SUvu@>4drf*3z5&vT^PP^ z_Sk(7i=G2oLPZY^w(-Dk9NJj= z|E6N#Qr!pU-HFD7888?}Qkg=AeG6ro?Y6A3@cvf*;*sW8c)!1GWlvV2{`QrXxu^-ObNQApQ z4{5ansA1L*R@MhAf*w3T^J z55Xw$Ly9@ecf&c?auw;v8jh5qX%e=5id=`ce@rSivPGZj8Fz=W%rY^pZ6ZOcb z5F@|)gQ~?Zn(X+K5ZIGmpKGssE6F}i%%jU?{_P&6y|m1Pk1u1!UpEu-w!qa_^nsVo zOeS@U^$|BDzmV}ROAB~(>GS&BVB!sgQdOP%-z!hNlSh~MF!3*x_T1p-!>L! zGspa-woFA!Pw)>aXWC!D_It@_yzE=I#yDdo3zA#f>LTO)m$U1mAD^u>{}{nW44*Ht z+IkhI!S{O0P{11j;L$j&JJRJ5zLQlIWkE?Q+>Z>U673G_=7i}faoCu98T0A^0zgia zxkw1Xy8lV^{4staDm%}qz7!A`UX5Bb#C9y)7Gax7Ls(O_?p0GWP}MFktxgo-ZCV(# zg>yHML6vB4{J;EJql@3=3KsLyfPeND;LPl5ypR&h3##d?H{7jN#Ue$Aht}00(R6#s zUrE*29=Pf}asPHF;K{>FMi@7pr)Es!>d=XTbih<7RfG}hwZFHaqfjm$2*Ji&6l5N< z*($!3#Y_r1a(p4@i7A--izr>95x{N2-E3wUZOb@iVq?{}I zx)ufnTNy~rH)#)o1cWxO4@}b9O?Yw+W7AcRozN1y*1?EN5VXXN^~DLln388H5hw(8 z##XW5)-wA=G_l|&nLk7SDmSKUPg>1mV2!^Xw5(6qh{AHwxeBANj{NXhqE>DA`IodK zIVkXw)hZ>?SS&6Qi^M=~CNxrtyEh}pb1#}blWd?)`Tij-4k5cSvra|FLB zu9JmJW7<8G;T0$|Q_5kkjy*JQx_AWAq@s-EZ0=y2haHH&A zAx6Fwz-|iFz9)QG5%(pnBF-f-NA5*#h&O>AZq$BA5;MH+|aWK|j zeStocskf!xeGj6br`xN}`0EAn|JD3r%vC-%kx6C?_tSS{X7J%mcct*#ZHHFVE-~|` z&q9~!_7KvQOK;W_@JHA*pQ{;Yi`kBgjydU4+SHHY79bryQXG&Op3BQ{Rry2R9=O8y z;@a;QQS!%8^)j)5QF&;^Wr(I5mw$;ik@EghXpMP{^?r}j#5iyJNjB?A)%S7OV=$2t zQaGA}VNiG$r5j)~DizRSF?a7A>1V`V`W#)pmg)Fh-{pcwY)syL2-&r1q7AU!78i)| zp?9JN84JAaXZnsNvBP4;aZ{mJZ~W3;!2-PbmILrPt3G7G9W->$?SamD%aF3Kb@z#P)V?|x-XCgujPR>U4{JfvMYMphPM%c*> zbIG~s9Z>*?2#y?ex3X$c3#D;VW%V)^+QBz*)WF5+-1A6+rk;#M)6t`~ZBS{zlvHtr zZ9W>!_&sUqz^xB`P-(E?+ylQT9H0{^zVN%;XWKJyd-s#}dzj`ZR8t2UgmwDcj&|!TN5lce zekoz#b#1{-1-3Q4asyo7@%c?$ssqP#u4FQJRPmy`{3wC8=|h!KKn!zDZNuYgPC#fg zc+SkV5POKotR5mKbv23;YofU`DIxj45i!Iqlf21_yZVhq&)KlciUgorL?c|p4FVey zls}|gEEG0%CEIhq7pb*CiYmm2z=hhWG8!Jew)!zFNh&}?79}f$DxqYho1VM7UWn>j zVq<`FZ*pvRuf)(V)lFVh+FQjlC-SYnOOO8gkP8+#~xOls$yW1_5MREd)8|3tP1_s2m zv{m&9>)7zr^;($zJI6mS?8cK-n-*hTaMVr!f#<5$<6erB6eB-6E#mw=K0b2zQ?PEa zBUJGJcY;*1Cc?d}M^^Kt#%t&rDT0B9#QbfLj)^$x+u4T7v&sC>5{W5d|^>o2z=mAX2yWY5V8Kj;NwfE9L^9JIdkrL zzQ^+e%ZtfLdE20PnWa2tKBhAz*G*txjUGV}zu%Tbp^MFiyc-54^xeCzebqxh$7UdI zdl*+a2-UFlHT{mQGYW%p^SspSOFZ&rLw9Q-oHS?~4ik04mC>2~!zB1uqQz&uurWiC zk4JDYam%hvs{`4ZT$-a2zVbg1IP9C+ra2Y4f40S(crD}pT;|N zPJKVqAi^Jl&Yiy6PjSy2|30O>0N+>lMxaVUxaY}Tlz7U`?XpEQ$*iyjQNbp4TZ zJYpH(vOMWJ_9MU2jm1g(;oavXQIcS`C){}S7~-Yvrm)tdZZ9wQfT9#d18en9B^eUk zCn(3(a|nGnY5E#10odZIQs9znO`bUcN|A=Yu*#FvAzJiTlHfxKfeJ#0_baeNbi?p)muc$wVQ3|(K4HO*Pe~-UF(5Ue`+YUJ! zpRXbTbN+h1_|YMAYTYL&BLiOJu@cga)tqNla-DY&2o#P!a_*s&!urH~$%8Edy2Xhe&Ny13woY!i;{d^L7Z8Y)`$4>OD?Mr+SqzKg`nag^Z3y(`*)HsTe#M zsR8zhh2Z?U=f>bh9bC40 zWeWD1Z&=0u3`UxT(`;mA5q{V5&R0F+R09nWrkg#hp-Z#5t^y8-q3X&aaXI-p{}>+j z0C>cnSbnNg9xc#qyB@F=ti37yNtC*)3u+&-o1yQ3L5QUFE50m49%JTqom& z5*Y&odfHcZe7423+Pdz_RnHjUq4 zEG2V9Vxrty$g zg?BBDUhGiypsx*sw96<=m)<&9s(0?$X{@-13*gK`=e?MgE(CRI5yvdJN8u?Ge}|!* zX~x->m4)Y;cltA3SJ(o-YYYS7-H$b%(qk>3AQ zBJN}~b4yESaCkh*DF%0B(0&A`*MCg@K4sGjZ*r5ylCQIYXJBadAmr^Nf(<{RlfA&9 ziK4kjd*@mY58xN>6~j5_pp8LZ3tWHMwbxe0JIK-q?57Bip8}xX>=-7!zkKr1dnGZ# z5H^zXx(~45Nf?!=K;Lc-ets-!$LgYR6Gl?Baa};JhFAxfA#gPZ-UQU80N8@0igQEd zTuN!|46GUr_$v7~*_7xbYf|Dl6id}0nyqatP-4``aU%}Q@D?Mt)E?M<4FIm57I@u7 z;mYq;9PWVaM7r8HOfP}D%X|3d9_JZ9O%VR+pCxGkhNQr7C4PUyX;(8M*|ZZLiks%p z*`=KDwVO$Si~HpU%py)L?w^P;V<)&NdBNrkG*T^oKrxBK!`RvCD;nv8vZL?!A0 z^tRQ8_^|>es#ezE(qq*ReqZlzkE}bwn#K6z(lVH!46BeLzSSAgYo?rLq>r=8OW` z66U^$N#-Vomle#fa&~!l<4$;7P(r7W9qfMVY`+ZHL%KV2oA;c_db&p*xPZcmZZnE^ zFG{V_I*<Nv>UHd4z?Y}>c%74OQ5 z_rHhfLHS~~(k|XAei57U^5gA(Sn(ggTToqrykKCK6Tf0_1U41hqorp+X=HT8Q;Ym^v}!Z(`GkVlH>z*8!q> z>7r|ot)bQI|NnI01RV4pvhVa(Exlyb0#@&gXiqFAkiUu`c>~noGqu+#TO3)?_DIBs zxt7}F#SIbPK9+<=c#P5B>}c0f#^j}gQ31b_K5|XZjyMDv$Lxa{i%N9=$y28313*I4 z(3MON=i$^$#3)L=%)_9S+gDK#+0Q~mnY-5|m-qOPP5AZWP$36$q&P+GU)}S&1Ls0_ zMge##m-jL5cqkEwO6rE&lQ$Zif>@xEd?ePH3z6bpXA=URDKv-m-V5^Vv{z}NZ`o9PTK4)NbL1z}`EiS=ora{D$sbl2+; zi>$9x%&a;kSERy0w2Vt=*L5(f(!63Y_EFEJZZ1D2>+EMWrKd}EtYHF&BxzeB3_S=8 zX<^j5+%CoM)J^wU&ZMQK+wMQoZ~eoq7_4Inf-=RHU%oDm@)PRe-rmzY;z7%{YLwIT zGK@94p9?@R_S4OzAmQCsbpB1$j>_guyjoIdNpxmC`sCs442MlY7TD#ZtaHqa> zceC!}?lU{JFts(c;?z6`?#2b%3uhM$c-o;j>IOIxO&5k{)?)CdV~~ali84S{$hv!l z4|m90tUDA;!$a{wDIH4Ml=_5&T+#E&nd+mnZ08q)IGdQ2A$g zp-dAXr2N8N+)w?x5xBt{I%xV!{AfBI>x`&aaaFs#eOy2i{n5oj9n;JtSuD?VEhdK1 z$#@g=-+4A<`?Ficbw&Swm%Z^e>x87q0(NXCSb^)NS1hj!pb^w1`<_5iJUlS0gM)io zZ?1_oMf*yOD&3a;Wy*{&Y`!4@XoeU@&yT~`C8`hzM5=@6(V!lHpYkAobze+ux>2)% zz#Z34tiFq)(87|6Z5s1!YqwMb~1_R`YcVVP@tD!atDa5f~>it!9{Cn zNg=LhYyiT^wqT}{=L#;aB5~e9Z8BF;ZKX=ub#X9f4|vJeD3PG&g;!Jr_z|0|vPrFaD8@1+rzjNBn& z+m8>S>Am=|F6{1Tbn+1M<1yuP-cM}6#9JqSQ~hu!w(PiDu_F0n7Dvdapak_bdHKpT zb0W%r*O!K6V80^bQ@Nsb)*hJ{h(rtQF6pk1aE>2qgb#osvF4%3kFPF{vJ(s>W(h zR#IexHw>W~@}MTNNSH#8_p+bMK(dW2MEI3O8VM^opHr|$+LJ2-ndtq0vUFO3Q{emj zWmQnhs5N}TOaM>Dl33`WrcaEc+_+)HGiIB_2>LK6`{kj3Y6VjLz zcGfrG$&PfH=yK8hFrH`vulzkcH<8=*QYNc?VBIVsz_d!3*l5c*KE7LCF#KVJN&MgJ?s$m2aJ!$N!2 z-eL-de}*=doD8DQ#C3xB$vUpdFR@c{ z;m0poO-IkGb5*5^#VgVqF^erS5@Fj)?YhIBbo-eMQX-)=+3}~9i*+m|;;0(8`4;V( zM4MMqhue&uq3vuFYMIxzB1nV77iszLH3}KM)DWb?53L?at<|{IS{2ez-8L#6(CmP3 z2TT4H^k*^UrfrN^3y$ZemF0~;W%5xQlppVL0vHf7dS>rXoJx(yUAwJ*NGo$7v{>6v zoaS3H4&wze&#>;J2|{IkZ`Nj$#cpTXUz`c_n{`qpj9sAw+>S)j`>Hy7_-QsJvipF# z6&;4?w=GuwoGdz0LP3%}vE)%YowL2aF6da@6vV_b!(|-T=*E!Q3tpAd4RCE5MmGID z>oN&j6~Y>v3;At+qVQh$**IVwJes&If{ujsb!q>hfn7bx%040(bQGs%QAtmp=g}36 zA+czkGrL?yI_mR3Q^hRm3}S|iln@z5d9n(Dr{LtM-R~Nj<+?aPv@VlOg-|$UDONy; zPt?V1!*PemSh9$Zkp&xa53Gbd&(q84NvC8Jv+2pikv=9Qe1zLfRU__?A)lZYJdl}8 z9iu0r1xUBpTjiji%^jC-&n318VjY(Q<&eCCBX_`2Mw&l8m$2UKaxf95lP>CrP4s5H ziE%Iwbksbf#9aC*`baKkBEsI;`xG!j$Qe|?Ae_Dhx+QLk8q)t!9vWUP5@TAR2{BZv zTBzqkXXI_9(1BlFG9sN)Y=%b&#pP?k)c^b!ft8xZTr-YZ z;Ly6NdAq(!Kr*L5fX0?6M(O}L-`A3HG7QVT=;iMj@YYIEmy<#XGsgA+{EMTT-1}Z-z6cP%?s+? zSvD>lwQ}Rm36NRCkFi*(`RyuWanV0CT8fth2C1qQlL3?UHBx!(S~5|lNMj~IcEm$b zk)--8_Tt+Z^}oG4h_oFX4FNXkt=AyL#lixxu}0Y>YJ}CDo!eP)0o~km|KLPz%breZ zfN+`fwxk9m*$(5Hd7<2+fz%yyog_1)>Z1GjvQfC!HZZ)VKq7ynDHU6EhtH!gMyVL5 z-v*iHh4i8p0e3zEXE`#dL})-Eh7p^1CuTv*W09-qbca{Qd8K7TQ%(` z&d&Pb<17B=pJQAucyfAts%n(DEQ3@IFQsKVQ@_`oel)L~WcD;RsNPEp2k%4>+uJ!i?g?xor z-iMIGZ)T4pw2~N;GTS6bIxsk>M#Z6$h8z5q{{{Mw-a_W^T>G&RwOYSF;(Z>LxTjGW zdJL;9_r{N*76Vc~I(3TOu#H%q)FF*m@T$^snpS8pTt1Ys`>*_ZpWd*A7Gq&p`+R2A zZE)I%K63^;4w@p^ZVJEnEjY)Bwk38&Nal=3a*QDq*>mhiK;zL}Z6r4$&=zTBD`H+%YY9PU)KY}oyib?+YK#-|BNCXnT#~>6xXe*x6H36 zTA=l#3iuN3Rb3Ir-N#t~n(XqnBo7&eMlQ&MNx2wnWN|~NsQ(FSe1UU}Pn9G+cG(@C zBlKJ4DHctuOA#zOEWr8K{s>LOj;O!VvTBTGDC;^_{9&(4n}c2C4oCm>33X;Dv9e09 zFLmx40%X2*FlX&-w!$Z6R_k}SA+?Z*lz1niL(J>8zrsr8;jvA1cr;xma0zkEduJOJ z@I$nZGO+ZcgE}p$93&RHybBK%CEPJJpe3AulYLK$IkVk%b-&h-mG6>y!kgEJ$Tm|5 zHIcSNFkujho*UM+>>(tzRj+LMM))Cc;GF7~qPnWnSf&XAvDfT^e+m`dsfjy-s+a{x zScEQjJWT-_kQE%dfTak!yX}dTYP{(SNjnxK%Jycj!y@lBbb!25PQ^ z%F-(b_$;1KvI{i?LnbiZ{MTJQ)9mlq#Drl95ed+fwh+#L`B!(VELnYrd!Jtq!$S~N z-SnXxoo_NBlcBP`J$hC_%RQDwD-BE>gbcRuVU}rYYv*qQXC(NCt($Pl7$?ZjtM{)a zG}~XbD22ypa*vH7Nz#YSq7~h!o8Od2%5q1fWwctfcrHXirr`& zn>8JDX=>t&W07q%V^c+mK8w63R}%{oC$3_>cPOquv`@TJ{9t5WOma{LkN)f#;25gPNfHH2PDPSw zUcK%wkq@$cBElNo;9UFW9WZ-SfR=#;tRXfdEQ; zksk+i!BTKkY`!5lfIB=Uw$vRVMcs&(|CSL{mjPle`n;WX=J1kOBl5HBaR_x8ex}5@ zhu4fLeKZ{EL)QTB_*pYLy8_jsw*#|s%MbD-`Dc8GcAO$G%lD(Zl*&g|+)+yY)p!u;-VLez%E{iY-8cUG9cZ8hr048Ilu<&%o!&muQ7 z1kU#m0eEOK)I((mBXmQ&yEInbLtS)cK#wW*O3=N|GAkkuUb$50o?bZy47{s5bA_rw z&{0>@dPqD)iQ;3r0mTbuCh&-7cC@~pC5uJ)e0UYMlFKJb+$gp7OrkLsXa#m_zGJ?l zv#z~)YHX9#4C!q<0m2kxVu~?RysZjwhQmCX;!|I#pu}|5!!n?_fQS9A^Z}xUzI-*B z&y!wJT&y0mZwu2&Bsq7Ahl`5RXy(NM5;m|Ohn;gWt~a3oyAur#%L8ca8d*?^a9KyX zt62&K`rSTisXk{ou^Bw7NmkJX?a9A|$rj9#$gxANZ4rjJZ5((dZqy6PUN_=Tc$%Ma z%eU)DHhk`OII`QI^L^yIVj5?<%nP11FxC*c%$P~7GRl?!Tf2ACJ@|SJ6hECl(Nj23 zWU_Vc(*Yoyn&<}3A>WEXk8Vz$AR zoxAVb#aOBOnUBl>20b(w=(}p6Ni)%ZB3w~^ zYj>c?MFEQ#Cs;*bsdRtUj5i;XO4nmb+CLBr`=1@F^j-H7^1DkUH_eSeU z@*B1Qzg(Dh27uQN-y_;tT3yO^a$aPyb^POc!F@_VY4o{U%=X_Qyrjwc6fzCz1&^^WZpH}VbxR`nkB%VA`@)3O@TK2 z*K1y4qAI76W0V^A_V%lix&Q(xa)R1l?gxdGpT4Z+aruOyRv12r;KcSE&y%`yB~T594S4*aM_~YgoyjI95fmh8 zrIO4Fy8IAVjnc1*Nz>js>EJtv4w1;pgycdL`;5p9-$QSsP-CK+=mkOH)TripkN&UK zdzQ{0*GStbXZ$SUwb^J~uDdZVph*btNod&gc)rTSUgoDlDChRZIXUKr?;}FK=H6a} zfWZb8%s+TPOb3=)dLE7-x8m>e?Dai%5;ne1VJVw|5tQ5B$#|pmrbaj4aU`Wi!>Eh5 z3m&PW15-B$skvy!Orbe46dVog7%C72@Zigagcf#1E^4a$8F{E)zvVceGzc=SWas)D zK`O2c9A`fEBmiL`%;PJ@)N{}!x5RbZA8v|KU$2Y}&PTSL2w+^QcxFV5xCXxO45xWu z>ME*-V-bc>V&A+!L$-m?Ll3%v(GGm&jt1+3eJJew!)Q)|Y^}~Uj-gxHQzHD=K-TQ` zXF2$fYOAK#2H^napJLo{-OBl)b}LV5tz(5JLe}~PqVy)ZO6$}XE`}dVG;&%+uw^?a z7W$-bzBtM{rhLh`F(oqx`sNXhA69{J=Oki z2sp6nNS-nIQFtHT;Szdi_nBKn{_>|jWA(_)b(Yp)Ky8YmJeHBs6@J$0$n%iVyLNBZ z^r5<77!x@=gkRg>de~oHe{^PPIZi%qWe5j*X19)a3`i)-t`R4va>r7uc@x6(R?*4r*`~N&=Ocst_$Vz^Si$n~ z$B2L-bu#`JZpLI6g$PwCOfN#=qWH(;%2*YTYXnPrTnrln&nIf$2~0Jj`=!r*MRKHzrT;k`TUg=M~=)uM4* z##}*?o--W8>N(xQaG9ER;SqsVBuD@**4C`comAklhb%4u8gS4`=W1MGRU`P5Q)_m% z2bskJlT?Dgd$|e@_oBA=u7oC8a|>4uvaO(R?rc_n#UL*QT3PJ7{fupNQmzl4)qi0l zL1VDR@CB&XvjO5ViX@ovY2KnMmP-NU#3g_`V3=Dr`kDFR6|y}85z;k8LUjCL@5J~< zfM4!a00@_0<9oS$;%cAARI{tQvPUV|OmS1S|J}_VSeqQ|4EFz&_i3`^tE8u%q(z_~ zso`16@2a6sXoW2D>Qn4Hm&@pH<3T!(XgyT>=TDAfkX+fUGac)_5Gs-H>N%#xy?YPr zguju3dYbampZB87#yF3=sQ`*6`YtLeHM!oZU}i&o3Y!fy_4zHlHZu-65zBnL)=Uz{ z1i7uU`JhM3P#xtExxm7_IQmp_IV>D}rJCAAiY9)_FiAWHiw@mh z{svqrZgZB=gEW^3IfdZS+YE+Ug{~nHxC(SDe!&hXl8uL%_>sdPjHP9|6AQ)xH3_In zfJ9n#t2on;w-L_}#Z;IWo6}tKA|pZOKkT)>OF~81H^K8sb;)pYeh=ou;yeNqn7u~hK7CJX`=o>%f;@=-7i3x zy}q0NORUX5$g#o0FMBJc`?5I>l55DFHNmvo2^JvJdmAEz=KhHljEk%vg|WPYxDJ-9pGvV z>Oj;`J|N2?4FJsBM)1X1Xe&xFTWqVXB0WrwAn`y>eP{y5idw-4zIF@2OuaL#8{#l3 znWVYZb%U(I1?Zo0Kk}`$u2Sr24wNQqRb^}7cmSDB7l{EyB%%n9c|(YIn6U@RouI<= z)E30Cr-#QO?rHkMLu}}3u3V(59*MOrfT<^Ys}bsdB_JDXl^HP70AN03nw2Q~s0&0y zZ60|W&nzv?`||uu`en7~DDJ9Ea!W%t*}pZHAdYusZ086u;jcima;|iq*~xGq`1iy4 z3IE}#$6)dLw}ZUe^~$-|*&jL|u@jpf_x%mn2L|Y_H2&dclzr(8Ra-2fI)umw(S>c= z!Vw+1Iw}Ln3fnK!$uKS<;pEY-JTrDa@NyYUa~-|>H4{AYkQc|qnPxW7-+e$+SHAPf zID2tg?KxV93iI{-^soW}raYtXdrc}o3EphzU=jfQ-MjyxJxQ&28T83!BOB@ct}a8{ z3dmc$kTB zvI{8Epqi@WuDI%tixsO9b0o%x-}`w5Bg~>zZZIn{XlI|>bLQU<1lRVo&1Od`t4Ufm z$ZoOGh7Q5WS{Pn1b3KeR`WZR}ikFu0Ex#C^^Z^c`DRP$#D z{+$}=&?F^yvTH>eol{W(^NS=HVUJt*%Wc&4ac=KFkn;0@wk^adUE;R!ae6Qaf7bnU z=|kCg726b=bpP#Yik7*%gQ|$S)y}5h+hIlMo_gl%w7@XAnB)o3yejoYLm!v)Xd$I5 z61(d3IcQldMXOjgo9j`M4)F?2^_IB6!a<=&6wmkrMdNF3oP$~2IsEdtVNI0!x7rgX zhU)`U()iu-;QvA0yQWZF23uY%Q8*GDo3kXx@$rgpe{OKM#3mg=uW34>gog4oLNBMh znbAW#sNnFAg*|}ce{Bd!O&7E$<{c;X5Ss#KeQr;5q1IpOB~9N9xp#z1Jb&YA+NS{m zUPxmFP_cqiCu9-9f|-pE1X)%3e-E)v^rKh{bKafxh{awS6Eb#+r@5plz0JOL*npJGq^AKrAFOsO9;0-6dB$VCEIhG*hFYt00|&ji z8~Z#vo<-aKXydH^azQ>kmtyTd!-;c=CqwvBE#Z*f#Hjx2 ztp1U^QC`Q%>=5TZHwBH&E=#-2`%o9?{Vy5+2;C50B1rE*m7v&79okxn>hC=?=mry9 zBZv^Vn@AJ<;Ml547H~2UsIV!&1r7h9$~3Z_d5n};Jq8&>(`gf`z{ES*-=*Q=6yL_+^;QVNjk8F~A!QA^n5};K7d~m0H-} zb@Keg2M6Pn4gWOe;|2$O-l~gy3KAI~8pjns$!v zAn0y`NO2sSGw#WXMop*__YPNOG};|PF(=HyMfIjz?mz>uB=ylb$&}NR0tBeK=jK@( zC2Hy{g?G%lO4d>7H<}2D%UVt>^s01$Fgn;(RM^rV&v;FPDfV_rf~7$t@~>7Vq;3sI zM)uyoW<+0o&j9KofbP9H5pj0+_dQ%LW$HiXXYVloMbb7 zmj)$1<^%R)+#u*XLE+eIIh00-ZT9-3J5%2ye)`C9RXoVwTB2;h33b1!1ibAJ?)r;& zmqI5iZ=Zp3M+6>Zq%@!fIR&HF84X>QIH?BjBn;>kV)puw!Ia}j#>#I6i8o+GMs9j( zs8*6(jNC~rzx`x8mip&bpzu0P6`~4BsxRY#zN5B<7Ib0ic;~P_Bis(N1DfMvPDTo?8=!Y#}VN64yII;TK zO-O`9)_6K>?VNbe|B7Yp{aZU^T!9jtZ67buSuE8+!SGhy?1YrbLVhc)cU)h@VfAU2 z6?b;d@u96(a4=4{hg&Gh!=YJB1E>m=JpUC!iDB+wt}(gL`ipV7w-pF(`TY0jN@8S`kh%c=Qjj=L7$sjR*+rnbOnz) zQHl0ibV4Z{ljTC+AIrYWc%D>e|G59@X-XlEb__M=@*bhyl<|g7oZj5)8KN z=ldgkPf2Aostq40W%&~ivbV9uI38TH)Hckyjv-`!rmeNs!UiN_8!Tw-^$-Af3k<+f zlzE8ljFjIXE%}9nyHK|Q_Za%Q1NBxZ|9mifOCM5sY%eZO%(BG?s-{*h#?`hJ(-J1^MP&25^ zOs9?MFq=85DA6>B{rkKiW$}g5seQarZ?|E|xb6sAAZ7|A&Y{6!G|vbQubW*(ffCIn zA%2H8+5%pYfv~pzN!6-Z-X5kDtpe50)rfvn>Xz${hy zN%k%tTY)Nm7QE+HhwuycK8&>zH{$TSsL3084?9|(JWk)xaX@o*Hm?*Y`xgF7*e@SW zhN#8?GQ6!{&v7mmIShV!_Oas)%B)L3eT^b_rF=mq^gU9agESw-+a1djT6RaA6mr^> zm&e-Y%6N6RtflRfvBExw04B752EHKH%P}=WM7d^XqeNHN%c*Ns;|)FXSKiKDfPfz* zQql=P&VFlFl)fn#t#cht;fPE`hvTNxDoF@_H_PylvDHTh$U0V_mPgD}b$!vJ8k7^ygF?SEqc(bW;J6VKao$R;(2Zr&;0}t zg5XmvK8rvAZSEU3pb|B+hK(xN&Hvl+v#v1M%7s&ziy7>*gpcQ=f-~*5 znI$oIH(l2pq5ahvQtiIiuB2Kex0zy-nX*aQWqNK)jiace|K}5$;hvErQi&@uE+eDq zge}sN;Mc1fOJsZ=9@ivk+|4rq_>$YO#^tu6K*^}s(1C+2{z1W*PF__^ILoDQxQH2l zvrTCEAo!d``&IbE7it8h7sEw86IuqY4qOkv{m-#q=^6|s>Ob=vAf-MX zptK8g4w%n%j%%3k{-ARNtB;dnD%AZKo;^7L9DKB#Uh?H0C0H4Y(6#uxP31$HK@n|S z*1g6a4wZtor}`vJjv2>&UlNKjQ#N&3OHhsBiW#Oho#6b~Lm;z&SpEHC4joqGnY0I1yZIi5$Eq2}|G6 zm~E868AfUxwEv+eMR&ZP$)hl+U!jFptBoo!@nH2m^dKEB~GM3eN z-jQR@;M#gN^04#(GD20p3Dggih~%65M*qFb9K*b&oeXU?C;4vKZIp#8TzIDk9SF@9 zA(zDF*z$8^J~7179c?^6iSA*^O0}eu+%r7{Cy-WrOf|!Ut6tyz3~Cl%@o=a*-_&jNS?3HIEkmT@h)e}8{`w937z2g zFXWk1X21Ol3gr+7MU0|l1)`%mZCcEHx#mw$33G8oxkZ5uuIi+m@d*j&nC3{*4)SG{(w4 z-V0j)-g+!NtAlONks13!qD$F$>mhx15X>#S^qnIvW6Jaafo+&yZ%ezCVuwKXWbKAu~+ zT7#kvL6>Ixf{IGMV&dNYgGXQ5UBI3(A$yjXEbA>yz5OP|yg}@`E42==|;1243%2I=mH97$|=2$gQZKL{`$(Q7YG{xvmIaH z;jr?j6C*(aqDJN|_Yi5BacE}*fBrY5J_iouG?=c>dHxhcpTTGBT4RVp@3~u&!Rn}} zWQS_T9P4Cc!pBJ8Nc`P^eT!8+I&&`mpBhm4-A`vR*-DNDU}J2}Ja0pL6+zRD$mG{l z*l`;N5t~ImLcKDhMOZ=+4mXYz>E?+vU%s=5JcW!jWkdr|vR_3fp-SU7KX_^g#Hpp{ zD)nxQwHZEk^(y`J?!{vc%bg8Af}%))TVy1e zqEXK?ov+$ae_CnY0jB?O6SRjm*OvrsmTwhRz<7n?NsTtJP=L#Zmi~KiN|#153$Uw^ z@ZJV#{knxp^J4oTKsikR{#&x)cr9C?w&yG!G(#i!K1@TBP@dAcqoCR3}XxXO`w z9rTEi7JQ|EUjM!Q+NG$vB+mFqDJf4g?-gCC$u#5_NTDd9$%4MD6H2yW7GF;KZF2>7 z5>q}t*ve1`E02qi`*uiA&SnxSw_Gp7;St`^4jgQ03g>V&(rH)vqZAQZs;JAu&ST}o zD}>-XmG=ylLHr9$D7Yx$QWxvBr+FyxWtzo1vmc@A^M<#D-39WX_tg7L~~0j7m=6cBQVQVe$!C@YO{v4b~kaiHLcryXPs|yoV~a) zFR1itmOL)E%-E)fl%{LdIYrrZzh1LS-M5t}Xvj+so6{vrjXwBG9@gI5kTJz77<^(EuDtgTPMb%$gVYfT{4;f5iV0}Tq}}vCZ&qa# zVP$TzV!U*3zT5x5#qwgo0_!+udjEHF8YW4L;W*Ss-`odE_VUKEJT`;z7n9FI`MbiN zQu0EN>+vxIV^>jEzqZ)`2FoZ5Dk`$hnQBJbe&w!>lLWz1P{Xig0Ce$NyWOUbGfK+! zoB2QY;w=2Oxfmds3$7|$fju{d+)!?}zRt1&_y}kTG^^n+3zhTg&Je<)cB{$`^Q!{$ z>M8DVD|q9%Do-#aMb^4NAf$d3^c)8(Mz-?>2%F0ucOocknO&#lAlNIM0QeGC4f?hz z;_X)ma6}{dc-9KRM{U;}-GY#A5<^xU^3Gp?<{2;;iFGUWZRF+`*#OKpkIBF-#}-i^ zAF)sBaJ(s%*Ecw%=crK<{ZdmlK7L7|oxKM-;(q(%H{k$F(T^aDBdsX zf{#;zHmV}xQpWWPP`CtO;sr_pjX6+TTG7OyJ!&)- zXngvi*QMq6&QASLf)v7yPR??|M0^=r!J1F0xp}rZX8RkOur{&HBdC>sB_ey`K81s@ zeV2FqfJt@Y*sw-uCe1ZHQg!{p&}f?17tMO$2J-3qD)!tB?YV0zRJG+H6KC6{ed>s28#P`YQ)x-4NbxRJx#BNpjHe_$@B_Jv;@>j2ex@0=(H;~ zj@5)v^|5#{^|4lt2yQ69{S{mnu+r#szI*T7|`csAk;>!nrz=m^c- zIX|dKT8YV#>pc5=M^?G$A2ed|4rtB}bV}=ll0XOeg8oGjH1!F)CNpyf1VaIk$*;Ge zxWf<5HEkg123e=J;G9Gl+Vy0@ni)BA=Nco#mlA`Cs5DH{L5^)|^U-N>nqkb?J^b%oF!pHIXR_@6@r!G7WstKD zl`clfY0(yw|9T3}dkfUq9ThD1Xs-v!um&$rOn;Sq$9W{RNtpFDMh)y0Q5ivI^LE9I ztT}C8`v~1!1oBb?Vy^!g`3~yk0pZB7kQmU;+*$iC}Bxai=#gZj#mA9 z?#Kq-edg4rqp*9QLNIY(W&n9>(loP`RlsLT=t1-PtegVi28$e023~#a#7g#9n89cm zw*g%EG@`IE~t8z5Rl&g^s*k}6~*f1_Fg zkHM?qZ$hf9s3(YClUBIOsw^Q*R+78-BK25y?uR)OvieggdIeL0$iHrg5s6F|yd?2Sj za;BJ2K>)wMj|XG&t%lOVSV#+>B4*OYCt-ZnxCV(l)e+>B9chLvc8HuazU5-s9_)pC zznF~DfuQSS=FMsCWmJek#UH);p-fP1d&Vf|v0Uh#FU;V+LRR zWmybS5oY0fLM3L{?lJfybq<8IQ0DGINNfM#Nbyefng6FzRJ4GzXBDJY>Z9Y41L;j0 zl#tpg|A+JFJY%HA9SIE==;KJw#a4L%FYUK5RZB;nP%|X>F!b*UC`t_!v1=+~!Xy^6 zPA@lI<-{4&i!m$pr-`*^ZXXV!ym78G8d-C&jz84RnIm3WWB>5L?vo0x`!0BWT^`8hLz^}gisLh*S_gM+&Uul zVEzhk!!h(QHXR{uWRmFw44)mAH-MREK4mGGdTtK>=Qska_V5!2;is4O@>spqF7q*o zZbvp7qg-Y1iWK8aw|h2meMknh0slNxZqICvP%Xlx%T-xChT+TtGKO^Fk!==N6N$4?UOLYmDlfAJrGr5R08}nl6bufX-ImB@H7KY%(;3YTV zJ&H0-?nZ-5nK9I1C0Hj&l%aEa_89b`CUqlCyj)>}&$PNIIEl}_nbrx3n<;EH8@%B{Zenin>dv;d( zAi?BMj@~IQ{d?H43^Fub&E2BwOX3HL6yPr(MYeI>adl6t;(8Yn6KTds+Hwq!R}4~9 z%sUo%@`y+ieSeJZA|`=S;|z&+aQ{bz?1DPgi~e9P_x%KJ((U(<(>mwz<1^uQNIJjjb9akjBZt7w0K zOGfEDDvbEASFbBN+d+sOVNZNjkl8{ znM(|4=HI83!$jGg>p~9jHAI0ST5kO`UgV*ipzyRON|Qz|>wLt(tFTyUP28FvGscW< zcNsx?oYe%W5Lkyx%{q*wu9L6z>p*7_cmvQJayr+)hGY!|Te!*$d0k*?W$Tl&OO!1@ zQaGKQ3^+-1!)S%vn=J4nQv&pCRyoEDP??Q{*Zuxi>eR|$7@63Hp1vxKtWl}Deh}$% z?jEV#J{%|y67c8{Fi(PAh2M?)IOs=h{jEDuIlU&NJ0U*<$#_?#`1*1c6_Eb(QZu}q zIZYvIr~#17fwDXqVRIku%@0$K{H-K450|v9E03{&0l;yT%z~aN$ag3CtE45#1|L9f z574C8zxU-GLXvSnV@S!v%ZQL; zGsc$Mf5`6ZK?*ubG)D!S7oF}iWS!Sk`0v z$OBX(gUf5Hps2&EH3J=mJ$V_Ah}z}Gz8A+%2i;d zl7N&7pTf&5ft%A;KRPk~N6KiTwhR7t2nzfkW}As=(#|&5-ozCrTi>VmEs$P1$P}Q= zcLC;51srhESfAB0H1jzn<@()rD7u*@~Ggk@pTP+~`l#kXyOg`#2= zp8C8gb~dp{$%kU)IdlABRwHN02tu6tc7m0M@~uXhp<=4augUyxt2tkblNG$Zn_Br# zwB@H)xzGVJbB49RWd{rpopU(6h*7oY>zM6{#N?rs+W2%%+pNn%9DJ~A5PH<`-YNG&2u+tEHNdzPwy8(!@-=(Nf9O%HQ0uQ z@-O9ZtT=SBgUPY$JU>-sGRYd$8ImCZDl7K4zBqAyw{tEzJ~kk7n2q8HaWRS3XP` z@wbHRrRM-BMEXATNOMu=+rn<;N*YOF2sIEvZ!DUJOLCEXJBKl#oMmJr_%N|fC0)+0r#IPRLi2S?Cq!OHIyTVwD) z6+r^5+Oj;w^F^9HN?B+afwlpzg#~Hbqfp)Za4u_8x=}pbX&wJucT|} z^%VbWus+-Q1(XA-Sp@P+8& zoer>DU&8tO5$VOgZTV2_VJgZu1n{$4^WE43=o7ax?f@EUBY6zA)~J!)ivUGuSXmJN ze)wJ61-~|R!F*3T;IMp!16%uW2dXExV($>Gzs-&i)F&T3FUwMBMk~Yww!i}LajX2b zOusp4m;Dwpj?#c1jJeeF>Lfz002D^Z#V+rfBe!M}&v;nd!6Do&0YeH8_(|)_FL|-M z)C9>d`U1__jym^NgGP88OFDdRindtMOW<~+omdoey>F6ORl*dLyCHJ7x0dmsk?{E^ z%MCvQZEtjL?+56S=iH-4OU54$2`g|zn7J#-cV1aisnPc8PhEye=&v0KW^#QacsD*> z$(&A1=`Q$4AplL?vHPZ4e)JhVi9HMa>YHDb6W}7`1w*I1Kipnu`7zWkDWb9+gioUrJ9-oW*$QK7N{3Xl2@GytkuvkFY zFx6I=sz6M`g<%6F6F==bN2UG~*1EeL1^jN~%#?P0)1{j#$N}I)n+E-l17K+BLxqq7E7JUlo|zgh_w09F{#Xf=_W?5&XvtL716s8`Rv${3I@BgVL=nj!W_dp6hK)dtMwG=78~Z@IDwn3`8~=n0KMY+cBIi^zvjJw z{FA^K3v&zRipJE2?q07{q;c{k!n^=$hxz>mm&d((X^d<8qb1cDC=KyE)}zU5yC;>! zqCDDyrNZ2SC!aKNPIP#7!~fZ;|5Ius%NGK8iUwQ?(*1wmli%rA7@{j@AIQYPVK|b> zv#nFV9#3|CqeC`^hY>MB-TsIar{{3Zh5O{a&tcE9vfE}7gE;{o@3P3EbgtZW#eo5g zCbr%Q5=~P(+m49?yWNXi?71Vx8bo^I1BYmuDuVD^MgQEFXfzsABA`!^*Re?e*(qTT z!2eEi`66YiS*gLHIH#^~Ore0C(<`Y@$@CjySGeH+xy|Rki?G`dmNR>~2>u5)(#^fp zUNHnf4UvErY!Urz@n!I_>(e=9~gVj-2VhdJFmB1gFRp!MgT zqq4K!UvrDL^Di7;|I-dp5jAGd2J|~~$M;TO^vT_*@IMB{X#M_6GH;+Y^vT#ei?fb5 z?OafO)$=$10bg|Ee}2a>Ah0nbATRwl8>hlEKm^%Rliw07CFEY9!+mWQVC-^QNDVL$GRl+D+hzenn}HY7%suu$sl$ zbzXr6M0hopxIoO^L2;Om+MqqOf_g0@_Kh*etlw?OkuHcOH4C0EPE^EYFCcIsbL64~ zp^=#J^L3 z;u3A;tm|!XnGy(9;TlwMWFu5)R(?36?+Z(&|7e?%^9#^n+EON9Oo{w!dX;3#S!Tc{ z`uZE&7_xWG*CMqQFbiB+*taT>o$wq5a0`G=FXPIa+vYOj0$88>xkNFYwh~boN`sYE zSJA>huU5_W-~%u9{^M_v-?S*5fq)*mTJ=Wn$Kx1zwysiKNnc+%(^jv?;O-Dd_RXC@ zdRSEGR=EBzqb;J6N=7i7Oso@H{S4ogdgne(mi3*{_?IGiK-9NiW+eGT8hYAJ{Nu|t zE}yFiERQC1V`~A_4`D9q_aXVTP}m}mPgibHvWH!BOY3uUy?W>&4~=k))nH{IJGP zTeKF@6n>@cgI03h(CgWgYPHupf}EZ-+<~oO#A{Hc{!bHC#rEyAdVj9igs(qSACr~+ z1GZ2*FdlZ}*kRHx zucl6gMbe>1sQZ1-jb>Bt7&FQVQ?PZMC~MS z{K%U&gwp&_qu*tFL-Aw%UT`X)W z$T-WF*8`C0q;)yNSj*F<1}5u0|IR(v1T0_-<#a6Fe>jGaAYagMjeS0H1KPMC!d(=) zI;8Qe<_(vK|Njx(E~-D*7sWsZ_85Mb)MaLa=eIxz+QMlI4 zQf+at7u@ZPv~|+on;a8JGv2>56+&)Es%z!hS8fYXwS0GULww`9-C8$XW7RoaFE{)4 zNbB%UHXXdhQ_rf}#^E+r{0?!u*5@Q7?z@N!=|7ANxEAGbM#BpUVcw;Ld_x%XC!&?w%bN zWRy@t1CmTDi*MBnwlq?kR4GD{{sSOA2qK-Ty%BVDl856;u_e{;fJfYl0AR`V5v2s zj_aZzyS7*+D;#S^-GudBx2y#!H>~?I^}RP~@~XtJ6r2<9OR&_a#}`@E9Jc*f{^K_M zrJiO!+g>yN)$}+oZicKiTDCdPeq^6sV4XMD&P8w~9J z%(jN#$uo|`lE!C|xTLt+lPxOq8|ECP-lkb+sy3`g%hRb`N z>bQ7R(<6*^34FYHJ{bEjY3|~P>VuXjlC9zbN6B_OCdFeE_EJ~MFChjp_bEpX^SD4k zPl^Mv5g*ea)KoARrgNiFx7>oI{p6M@y%6BtKBJ{ zOI=G980C4FdzFS0BHHKbNc9>oW%C;gsLDPMrMJCOi{JrQmOVf?qcvT~g>xdYPOG%v z+WNK4dnR``Y_K``R-p5B=_H66l zkW&{XmTb4;4q}4}Q6;%~RcCbqsybg6U)H-p;=b??6qV8Kb4tKvSmRN<&m;n#KEw!h zmP_&2EXc4R?WE5~^mRP8)-#aBEPh)X7Pg~k)&8TH;xxPG<&^+96#P*gW3A%`-?W9+ zKG~^=mW#Jf#q`d3%xiViWK*vrK=ZiOGNDR#8XN^Dn@kJCx{AqMD zLKw2W8KyV}lJb5YqvQ`3HxEuQyx%fH$9~CCYuidAt{CnG9NSR(4s)Z%r;mDlf@944 zG1(8nf?|IBw2zPS+tlDJIBIp3m0_j+FvL{H5<2oL2CNQJ?*L8cxEhnS3t5n?4kEnQ z02811437;GOb%lQg{mh)tRGAvQU`5#SbVY-F`1+bq!`b)3+)n(zwV9lPc|e$uZ+Iv z|M81wnyu=E*1T@$k1Cb_5iTag50{geFzE+htb1YGuDCb2CbU&^Ej^BY_mkZDm))|N zBzH*S`XqqP`O=+lj(cl}utHXLs%G>k_6M(u5N%Tl(R^a7g46ySY7$rIr6|bo6LYsai0tg> zQ0;d#e4sY{UIIMn;9#}cFWw}==Dhtr#}xN$(!9b?ZF$XcIg`%Rgnk04k>fQTQ$Vi& z6iM_v@Z$4}r3|1K0M%ef9CSLKL#ka6=6HTGRvz-DfgP-9*xIWVR#Gv*c46Bquej0< zljo2Caq*kyEv9`PaZ1RgXZ#zWrXEDGauzQAVu;kW>97{F% zA5a1iZQk*OS0dM1)%-FTD}Uu5L>MrOCMi4|Rnpm+{pXuZe_!}Xtm;c0+&I&7Y!wJ>xyZd=l=rzn(`{ZE z_oOpQu_VwAk3<>(7GF=RFmtl4jA&~(YJvFjH#wG3-!6y%bEX64%Y$G3@gmO?x|eT> zc>QF}SqZSQGBe9&)V@w_9wI$7Ye!~{NnL2Inqu!yD8ZZR1+~#tFiE}gF$1${V+GIe zvKOG^Qg!l`Q@C%8sUR2fr(|&~ppwgWqsv3H4EBE3a9@R1WG)H2xY00nRk zkWt@ix?jM|8yBMXjKBj|tC5XR*M>p3gQ4bs^;$Au?U%rxcw55{x@ozoP|~y0h1W9H z&vm-8&o(2Jx+Z5F^8U^WxXr8tukC6d45#R4cuR_iFnf6!U|;ktjW2NqSbv~kqQZAJ zGv&?^xlt=BI!X`p_^v{s6M4#OazK@?ue!XQ11PC?pUVvMZ=S4-tZ{LwxFpAs=9GDl zv%w@PKF!vJf?0nq*=^reB^QY*C@%9?#wf9@^XEE`3`}mRic~teMvW%4OeZIDR0ZJK zU;f~P;h{el8N)C?IF_gX}KHUuP6+QX(o1#6#+!I!aB(yeFx3y>c4uMF;5)@XusL|XV0JGp=@e$ zvqYZ;wc%U^@~I2PH@!aMTmeU?c7qY#3jjA!w|{?T1@*R49}rP`^y;hb*7=)G2$l2$ zy)(z+*}@`vx+yP00T%S%%e=%22YjcHYDnK;3a*qBo$2b!A;uql@Bhe}`kj6#Umif$ zVJA-MBQufb(MDcTelBf9xI)1PNLqh&krpX{t_gFgEIdKJ4_^NQW!B%*HPAjc^nO!J z5hW!+ut4-n2pS^{Ses5;a*9yhiSHdFveP262NDVZNj9oO=S>a1!M>C1jgNNrd0 z(~v`mTh7p#ydoRVc3>)mC$z(YbUd*#+?C;?5VQivTDLrD7H*T`geUxLyMh=hm>GQj zZz!%r;3fnBP6n2GUlrr^uDqu3i_k8#z;bW4HB+0}IyK@cyjiLoMW^_4yI>~+Qt(wL z6L2u(Ffd+-_jV8m$RJUALKq3_E$)&@RveTeRx=^Ky#iK=k=u3Bfss6SumYsIJh4j- zsuc9)6cWXY7YKMrkqW$+v_5XSg9+)x4;{Pq=S>G`KJ0{cTFT^TncDA1HhIPjl9o49 z?4U=$nS7d)hE6n}%HUDn5$`Piym&Frr)v9^i9=Hxd^CS4QX|O^#~zXun->Zmz|5iw z2J0qR!7g`Z>DC^ZeHS#mJ|-bZZ8;6r4hPz>FC#btm5x7<11E8$QrsYPrc{steWoY@ zwYDY}f-Zju#o86O7{DZeE z6z>7vDs>Vq_Y0lHQ8064j7Hp8T-(w>2|6lvixdT`52RzPBUBdlNe<>o1of7Gb#tp! zFT?%LS>_DPy$_eyFa?e zsUkFU8vHc#=|mT|(~ z&$1*9bWn@`To7(mtm2vq*Mjg~bgQP{K!Y<|e2_>W9r{bNy({U^aN>#d_oZVjx^2wZxvDpu zPdQNFOWSP<1}}1eqJ6Et8b96JXxUMTtBG=(!vh$zk*}1OENd?ZjrTi@%`HMQZ-Si- ztSZ*md{XkkV6B2mhU}#yG-eitrx=@-w6mxDOX$fiIl?v<@lRr!f;#_fY-%{0n0t2q zO8}zuph@097N(fr1sH=VY!iHzwer}a5Hi=m%l%rZEoV&$Au9EK+g|+r5U)gKZyLn| z%>&+5Jcte*4ZhCfzYqA~IR#>*t$CFCuL2%UAYjQHI9#eXf)s3na1vwy( zO7g3e!yhaugq=s0iFBt0?pBaf5K;F`JRSP7+8_JNXQEM9#6gIeP_hR3YG?#NyXk$W zrj+*WD2wpx4URw5>xzXMZ57UVi6etm)Sy}4<6*rqv7b5MGOEl3p<1$sZ&$PV4AT7N z^_h=z9n>8n6l>a(QX& zckp6;u-Zg2Zt-(3vC_MVS$d{zqxxQN1=8zDLm~Z|j4~H6dvg?VlmFKLgZnwjvte0# zf9zAUq1w(V8?yCITA4m6U&XFMeF6Z1_InlYC6RtqUHFD`K}CsQpUux3e0t6{qD3Va zy-Nu3atq57;5#P_0;p4Bsf&Pv%fT7x0QsO=*DcCBoo_8`?Z-MCp$s6Y`Ni&vubrB`M;PeoM{ znCjc^@qC`EasE(Q)5@C&ErBA%Qm}a4PtrwxolX;x6gPGZ_!8I25+auR8Ahvf%)3nAK6k zH@)@VRyq2A>+1mDe!gLA)C*b%b|XA~2Tr(@rVD_zX3{V>j-dhBk6hr0etw7N7&=Ls zN=%m_TOGf!MS0aCNlk$gV0WgjBnrIfGo@VGtB~AT`bTD|vXuZ2@t)_P)m?5UEhc^_ zPd|V=Q_k##PBK4{FVIdx@Z0)7f&aTvSF6MoK+RYV%v;E zojMZEqoA5!ntLv&UDxfZ!C@lRLA_C>gJ~CpwPvX7f4jg;FEC(OKe!?PJvT=v<;T97 z(9^*swIhZt&per(&!dQ2Q7*8Gdl&w$7Z@8r<3mY6gz4n%u=|HuW@UrPxB;(UCg(fqzyIQyZOgY3S$JXvS)-9iYZXrEGZDfO&Y+c6cA z+yyB8kNCLpq3?d4=kr5Ksk#mAgA+*ZKLxfeS_oX}T*m=_MwP-(rTV1-xZ*^wt2{hs z=vlMH{?FdSz()keq-@fM1dfw9u~+=7xB~c%IE+Tr?r?m6G$l-9`hvf#8KLObQDl%2 zo%~>m*AQ8xd`Lh+YK^2F+ct#gJZs`{zvzc=+Bl2+Cij^-U07w|79G!6p11wOFt2f( z2~g$>3!Cu?M@HnZ>$v`?q`DiE?1swfAoD%EzXGFBOKUJ#g^F zgjNUXn00~TkP~4Y<59&&lFv~;j($FZ;tdTqOq=^r?P;TD+0+pOe!n7!5?FLfm#zd z$vd=CH3{$=xKm0238$pM(%2V!{KRk>6uGi2wq3zsr~;btzN3J~jcB#@H=~1Nhk~CE zhxwZG%M|-*rIo)SYg<3m+^+29wW8~hJI-b5l|b{rBU}M=)hP)W8IAfW-D@wRSwy{| zF(tL{8|%vj`rMqRmo1GjmfBxAxxzYA#t;}*3a+PI<| zj;ByR9oHc`svSgeJI~HUtFveTRz2gWLtNs?z*H3lcXPz0UkTv^&IvD9Z}b=7C!+}u z&fNrDHVdFR28{JyaU2#-#H=J}QZYoyhxddD5y?htWO*mEE4#_4kp5tbzuTu;93+zv zj2fn~N4lt&bEysh){Qu!vQq1iosL|X^xzgI49IZ(66Eu|#IXNF&me#CH(nB5_}mB|Y4C~l1`K~~gSe}8Q#l-aQ%!7UL4k>k z=hZF$D1S3v_h%{MxKaXWGQlr-ILcgshV2oHPp`icm?T1A(p?Y!9gBy=FWQ*FgOcI3 zS4Am^@grL&d9zM9Is1=sSycwBItrjOKGO3lk-l)2WPl+walrp9QvN{!(`2QCRJtZ?0LiMgQpnXgDPuYL z^R%`c)DU#~vH)&cW1RLEVfVGEwWIJ@&0|g-Okdel|NEDZ*q>QuUB2Y{Z-LRsN%jRH z=T07jP0y*CE%gY+559h=VJd>Q1GP04QmVi5adeT`s_n*g;?D99NB}SJuqKwM<|ZX= zp%>k*CE3u4H1Y8MkJtfK<^bTb1`0-Wa?@?MSn+}xK!NhBiz(1P+j{;bIGv?7!x$&N zG}vR$NoQ4i8$d_}8Udv}ZnV|7;)%L74F6;j%k=%j$SOaYv(*4{S`G%E{TomNE%38r zUBPc^zI-+XP%9|OAwRmPE$RL1O22Di#WI{|gc{}W007`h_>E%$7|)IZYHrBTY_9B9HF)Cl4B}betdfxQw-OY}ayh_^%XGM}edhhx#dn+W`y5_UAA~ z!%s(u#F|jA3uRCi@Kz%xWV^;*jr3kR2CgvBpe7WVeuf1^wIcCi-4Bi8Ev3&V`Rubr z;enFdkzm8xcyow9xx8~&t{ge5+^Xu(PL^FHM2b>Dsp5H^nVM+8{5P%){4;k?7_=HI zuq(SI3QR?K{d?>8tm@3@#+ky01l+0J0#jA&d89f28`3 z%K^p4H(>&x7#G->%RJD@rkaIL2-hkBIyMJ{dqBOdZLnoPx~>cQhmaF57`9=?z=OEQWN0=wUJdyHBl&9Z?MsM1q zZADk*10UvvL%S?`x>@aD6i-lE*&Z#Ew{ftef_5ay#zy6L!2|p#R^O-p05yd{iPc|Z z+HiccFN0`jqQ)qJm1WZ8Krf1C=pV+}2G}lr3btbEv1eOegoX@zMxj6g#&cS2uJRkWrZXw?cJO%;yljN&K!qx-n1x-sZM1^l+jpvZRnMUHqY zYA#R;GN;Rv@oAD)Cwa!qTBEb&j_icSbfSW*WqnG5^YwWlJb(%IL${e!`{d~woH}5s z_s418t;*3oMA>uBvOv}kWTjkW%<3}+IA1ZDH~ zN>Glhf@fHvC*$Yr4}uP@ErjE|4{?Z=P17#Uyg0&=FqtW=TIA#sA1_-)j~Zsc1y@Vm zEeVhZIVEvclqS)mErEx|i-)V(qquG3YkCE;&4=|>?-%jkK>9faswu}?X{aG5nrL$RMsWnT79uio%xP(PW{|7GRwxf<}47Y$ZmO+NUmypN{8*;yGH9- zzjdTCRtn?2{F#3PmcVq(9+7oOqQ-}Pymk~f6nuu`SyMip4ycXYD4gabqmZ4$U#ar-H#Wi{GkM_9GfWUWuxcG}f)hTPs|?=S zln5B3Fr(?U67amE-3mEqTH>%z7`Me#28QLd+J%hgqqHEBxPhbaU(pE`or1>XWS6-c zjktS_A`ooo;tu_De&o`jwhojbXb!GErZMQS7^Yx&J?uXmjW}FfA`dL_3G21_P1htz zn)Oc1l|;I`91vw2Lsg@9J5%lQCWK3e^dqi@7PYt9%l`Uwu%YU#iNEmT1KlUQ_OyER zd0KU3e{}^DmKC-8`euVq0X{oSf4W#zh~A`us&K@tJ4*}pfD)(6oAAnFu)hC4u5a1f z4W@mH_rP(&B|bT*o^!fu^OB0-^XVR&3V^p6j*?NA0rk@UE__~xbW5=f<| ze(&G@Hhk)i3;uvo{^Ki}e8`#NpWCk-jf6vWQINnTHqM8R1w#9bF5s3|rRjr~Qh3l9 zEiH^U3sEeZMM8OIhUViijEp6nTq`|0=mgLR+JL?VfSO*f?wR&GD#=B@xvOKMsH}_m zk^g)!0cBIs$x)ps3e_nqs~F+f*3b=1z)cYLJX4pK_`klRdUnB&_g&E=UUBYgAw4e?o;^lMpz$HwdH)6B)C zB9i}ncG%PNkGm2Cwfj5hvCWL*=rqWdV}M9AANpu31xM@##66)+vXnID*&ju^WNavy! z->AL)o7@hW$ok_5yq7_(iomsYX&JXxz;|ZnUV36?#b~oC^LzbbXts)hKR6PI9M*-?!o1R96anwy+okP_zU?Q^FBHe?d(m%UI2c}}|d!NjG zqJ}e}-O7=mo#b~CQ(s3R(%KYeMNe&xu1y2~gAX3k*wdb_NkdFIQzX^x60%qE)~Wdy zdie#G6$t-yP}&pYMIWlc(>7qXc0sRx{$eK)gk5STjL;h#JG1dPL>Sb<*(pV)Ghjsf z8yt&*=A&pYOtb!TPuw{@6V-A9h*L%JJ5njXH^HNUy z>-;TOd^FA{PGg<0U%9?{EcdeiMh(fM^`}!v^k?Z5q`&ChLRXRe;Wkk9OIWW37oSS< z5AtpMhw|un<@tq-+-;94dwtc)8yx;G3w~s>e5BJ_gXb)#xj>MyBNl{GzYNHmc1fid zIb7tqlxFhZ%3_R;(yZlP4;7O3ROduxnJJBxFJJ$|T9GhmH%y?+uuKS%8I}XRcTfr806{D_I225G2YGDJ>DQZq zpek~p7K$d()k$|u^?|uVh3cJ+6c~~nzh+d(?>hI*vgA4yc~jp^8>c(V!M6g$^-~w0 zXVW-=ZDQ_wb0f*vToe;FWn9YBvJ9FUJ*QWYbu*4)4Omhp!zlI^inlWmLA{`Hq`$hU z{Div^zT-fR+acOHwqgr48oM#=5WhIUp%cz#1=xkm+4uL?D52kB8FTWK)$X(Qip3nr z(MPuh`v04gr#Ao;a24jFx5vCeoo>8vhd|!-=!m$&bJlVVn%`pSjsAcmVInW!+sNCl0@tMfVKWp5A9U-vyc=AA9(~PQyZREQx4AHn84f z7(Z#{i&fnV<5nRhFRCugSRWJHnNhFt!a=SZcS^a>Rt++6TAoV_>+=kSgsD)b(j>tL z4e}RX5li?}kCvVX%Tff)hcc_s1VrrOoK<{0&VrLxT$#YB$_cZfBGG*-9NE?5i%HR3 zoDGY=%Q^PwFvB=L9YQieB%#CNUhLWkknW1m=a@k9*TYTyPrZ=IqdQ&b{QWpVd*PZ_B9=e1ktK(xj%L5|>danHm<_gPEI!@%qS>BVq`3?8=I#vm-Pz$6uycoS( zEa%yju3k0%FZZPK0XoI1YAdA!+&jFq`|%` zq}?ryz`!@5stT!x&@VN6=-ex@1dn^lh41e6lm8Lqavvi&MaW{MDr75*q>LEnv8WwX zYqjZn$8i{lDYfY0Q7pwWhf262hH^e(HKj^@_R@3;N{Z0pAAiesaZ>InpF@Lk8HyBW zJi568G>Bz304Z?JU$Ix2qp-<$S}x` z@B_C>Lh{vl#$dM|cQHZK_3zQ{e;*) zm2+USovv2kn!78I5S3$4p^JNW8ai!6y{Y2Ex8hc@?8cB^`A%Qr9o&&QwGIMF$(j^) z?(0_;u?(R;Tu$5(yGv{hdhLmht3naA4WV`-M**kRz{?)btd_ z!)|3@{*Zsf-G%QrqGf7i6b2)PGK*K>Ijv+qJOz?3ZB19Oi!|m^XzRJlLdjsiZ})~u zo#9MNbg1{e{K%J7Z0xdT?l@Eo5WStmIMB`3yXZ81j1EHTvEv1d&i$@vHd6lRX?NDD z9A>T9+#3%Jb5AY(8|gH<$Hcf0HS+YZ`mW|tAwz&1QqyWu0f z++7Q7;RxRE{?Ds@@*lDY7~}QE(|m1i3GP7I1Ped%@laN={&2vIF7qV$C;7U*n-=RA zjd;Iy!cg~0aY94Da?Ib-3wD&z_cWOVOFimKr>4O6tjYE$Jv2PF0X-+6`!Xlh=cTuz z4N!p(KgJ!<5fuWD^Ut0x)VBS&6L2(LDs^&7IGu1C-r|x%UH7-ec6&_Y`dPD0_=9AA zJ5ic8g?XD_S;2@W%EeGOg}5@{-mS_@Gc9h4mig#ZE@KRbq9dtH?dbebhMT^@URNm!b~oJ4vEY~z`Ozk zi)acTqkhEs5%TkfXMPfNRw=*~uB(YDYFYwrj+Nae8tp)efgo^tZ`?Sw;Hp&0AeHxj z2{6r&S|5eZuNV@Li7BS*4EZ3FrT}48_>;EMR0DnQ9gtbPJ1PnlD5Cb7hB@ZB?la$Lg-(QUR$m!ri=X1whd7DgvRU7_q~*4+~m(G?a&wmBt}N z?U|9C2QDTz-MMi?8B|a`DPha+_`YPs3C7{4FOgTdc}Zs{b(~+dSRNk0nXYL#CC?3m`jf~pgdB^Ay>!;zQf4Hplexj%!^i|VLf*4t0;05@t8xHC!r zbqCk<@+2hEIQ<(ZJaLT$g<$pESTST0iy$f|i-O^D7Y~;VF?{myX+ro6nZTfM>9spz z#7>Ch)QPUBRFIk@U|{brUt01goC3}WRj*OpshTo^qmIDi)zGx2VwDk7RNoPZJmQhR7^u$P6h*z*wl5zT0U`=#W zes=`YPEL8WRz?VCI868nk)FQr_mx4?;h-P@OR%>vsCX;kB_eo8b}=vI55Ym_6moJ- z{3a$KnmyS{V+$95iq=mbs;jH@z!$=xv3jwZR7HTv^qAO zMOh(+x%^v{#a7mFb2rpA5HBn};_bp#Do96)sz!}XQqT$}eRAMxoJ7^|0;|QdugtbG zTNdzXeW|M^>1|joMbd!z<5+xr8;lwraR^}z=TkAYlGNc$FXmNs(j?l~mPDIhp@aAt!&u;Lk>a#a16O?W=05JMGr9f!)O!|$nrh(72FpIG7a zY_zywnhNr&wsjgJ#?Ul=e^8p$R>|z~Q1G_W{H=D4kd;*zsKKBet{2YVT*!3`Ff2GR zh;6`5%jua(xTq?}fxJ{dWkK0!GVHYOsmZBm+{+yG&FOOSze#tl)5hpFy09)U4iAw(zR*fAlahVb7?Z1V^^>Cm zf~ber)aM6`I&QL74%VaL52W0kYK|X9XY=SP08eP^#kfQ;I-NqU?ZB{es=mN^R}WEjmF`;2 zMLUL>OdQQ-LiS^bYy83-nG+M)KgfebVp@AV*D$9vkh5AU`sd`)V&>xm`@TKEM^B-2;}dD!ST8BmHa04|sce57+@Wd|L3Brq25> zq3t3VM3~^X6tj~_=jTp_MKsw@ThMsbrB0>2+KzBu@#j>kyO(z7!vh?PabM2;$i7hX z$>oQdxR0jaKY!qc;v*B8*ZZ`$VQMt7bStjQbR(gD|gY32vEgmre(Sjb6Md~S(1IW?#)IiIU+t5 zps=4(Bg80(UBFaH9d!_KM<5wuI)BUa1Az9=v{PuNGHz8WQu<7B0@dYLZ=Ld)cEn5Y zYtq)&(A4mm!mCf$BDlW-`kPrw&-wGl(`cLy|Hb1dSOrbs~aT9`F!C} zMX}Ykq;~k7a@}*g#hdFK!Bbe=gB(uWZ9W&>hVV!CK+AbVIHfS;zjdBF3*7QK1DNty zy{8Q@{}ryIbQe{cw<8MDG1ZPtl*xfMfe*_hBa|Bh++r}RZI2neW8;8zbtqVZSrqL! zse1wG_12wL>tz-{KrIz~24N5WYg*b?eJ|bJ$jR11t2w9jogWg?zXpLYnax$#&%7vi zc@os<-jfP|2$x0B)lc5N?*neEm9)nj%tUWLJ2*u?!P){k8`uB7O*vh8oe00BgL`E>VGctdOYg)w1Vw9R@FooL&&+7 zI-lQG!bY2>O#xU{SuZq|ytIBFoW|Y`{MIIX!zM5kk@FLlOctQ2Fvga^^2E zeX@dSF!Shl0t3z!bhM~%tr6+}wCOrh1w{a=;xJXPYb6W#&4J>C^gWIw1F(qUD0=ha z3WgIEO`$w+B;~|E#Buh>hK$qPq)P#pNB-y%p%MbQ@+tv})Xf@0WwzZQ*=`18%Z&VZ z#3i)5^MI{7@YO=cc~bIV@pyCx-a@yRK5Kg*Ty9)AgX#t;POC$NZ7fKUz*2e!uV+h* zB*ji~%3USM9R@F3B1Y)&S7+Eq$1x>$+g5PFh>!-lq^ry9G(95jaY zRe;7>8le&%KaFKRh%WWjSMqzMFku@CCi#0L%%i5?GCcWnL*w>bvBZI58a4FknLHr7 zx%;ih@7+2~9rn75DorJPyXR~pw#t9ri}BtK`VpI^@(~d8 zbQR!s-a9G1PmzqT6PyqhGLUkZ)Q4MAB-vI%DQ&?VrL0tD5M;_$`*Nd%YSPZGj1ti5 zink|WC{UEwbG2SoO*s<>VQQgK|1n_a;9(H1J#In&fVL56IdU^*%!*!6Hi7~@CzVpddnO~OI#WEj>2vH|Ev8iQ4HYy zb+zFw#KVyHhqgahh7iyf4sVPW_kHxrsH-*CQkBdqwBk+7!muaiqey1f2l!bKH#5cG zBgOFDRMrx&g!1$Td`@;@QDL;;F~Gt6w~blIN(3lbM|(O|^Mmm)d^9}F34wp0l);5^ z*+%@-nZ*GVt{~;8;q7W|f89ANNebokD<1aYA1!0wzyf!-gv}{>>gf&pjuMN4nvI;J zNV9}D2UC*eg+8rOa-=n#dfbE43aH;x0P?C%AbYHt%0{Eb9PKPq~4V?5Xb z5dx;Q%qkNlQ{FD(_j5{;JWVxMjkKt?Z1%0>kMIlMuHV)XXjhVNTJ7Do>y(n(4 z=;Ju97nlb3ZQ`|C^m%h9z z4TdJA8;dYyfXHT{I4pnRQciIP&TR zd;cS*K$Fcab;_xA91S{5OT(0>kgji2^4cmpClr()8$kWbZbnSURCG2*TE)b zWJ}jJ!$!(&4G^?aa4H@w*CVC1G&~T@r^Ay+j)ah93{rZ3-N&N*DTctATA!Ue)m_vw!&!ppTEUpA)70bQZmpGU5Ol#i%UPire8s^9pDqNyWTXJQ_+BIoktLCM~L5t(NrshE}Ny)9Jv zuYszv1c0T-XnGa1Nvx?SY~|ijaz9r1U9=^`^i$?*WD%++5V-QjYJ|5H|GM45l@z5I z6nj@u-K#M|M$vu}a(%N^MiRW9E7sw~bjE zykJ1s^gRoIZOpMi=f{2AkH7Y{(=iLNh(Ll!YlnTP7JU+ldslwdHAEtNeR$tz@=Tac zF-oTM!7=LX|4idi8bluE(3& ztoUyyiI(;{PP%!chKA!*qFa^0d-kAy4ph2LX}(E^xK+HyOV3*fC)a)m9FwL$s=G=^ z)E5b4U1>;6|wzS)6E8=OX7SJFQl7@2Z2tnLbbkeORHnYPo}Z7WaAcXx4IU!CcN9cd{=B(hR5IvT|d@eDOldl1Q>3fOuIO zOCZsv9P;Kc4u&VpUZaw(N=k3_Ip27@KQB|>n>#PoYn#DLg1ls-ECTctzvIj@oJ0^q zh`FV;0hixBvSJFa4+EM_WLmn3t6C4jI~J|;yF_n8wKGgoaZ%-(5fY3`ZeSt>&N$uy zC$sC*OT6Xm)pKKX%I8*Z4w)P)YEpXG>ReinW6by1*<*g|qTrf(gLxeup77knNC7e% zmWJI_-sAYP`^HHRqZ%sbuI-nRpKw8D^7ZxhAkoG{HD(Qd$3ZIAsJR)>)AwJ4oawhm zL(|oK7%YplC81^&VH;^W8W!!4t9;7{N@qxGHFYvk-XT=TC3)bi(D<{k*PS#Lpb?!U zkkyypN9jlKr#r1VnZJDWGZJYkL&cQ!1Q|_3@g>0MnDe(wtuUZHn5c8mjYqNmDYI$%u84>5Ul^NsMAFY}@ zin@HAb05TgoV3};sM5;fcz=zix3T4?no<4h^hQH=z#L>OZjk+*C+mo8pvUb0L#!{X z66fW;#>KCp<^Y-x-`8B^rsC!ncy)r zL1{AAZYg^Xb?7dTh)=d^5Tx?R!r(E0fRDTq{>HR5&;vx_gJz-;yT25e#j2c~ohKhe zIH9O2R~n3>-YUhfVv;ELCZ(3fDPYFcVu0kmQiMGISg9A3f7@q)|479gH_r-p9`KmN zZaR?iQyEtG8ilt~CO?lD#a_=%8;Tyjlt4##owsdnv%2jm&iklzmkJtuzk|*j2`d?7^ zSl_|>UBS+Lci1aU|F zf}r?>^fh_SY@HvHm+f~=0LuKyg+tGU z+oqTpDv2>W+(UrMqFyoO6O--$vp{9^$NJ6nDej%a{_Hf;x@RDJ8mPl91;!*t-Wt>aRRt9(zMMdQolMP8a}H|os~hN&#^qawuKTgr=KK?Zv2KU>Me zQ_B01XI&V6B|MRN%q%2s_HtZd_TPjA_k&HEcPT~uWRTGsbD<+uOs)p zLYg<6-|K_##EYhxE)bkX5jB#p0#s9AAMvL#)*5HX$0U`nFyU)xKXcBi5a@J)`J zH}F3Agn%{u2o?FO4 zk#qVSL&gojNpFx7QGhM1gjNb~L#+grn&ARgxJ`*FP1b=fJay~S9fdBCwobVNV@48Kj{a3mXSsH(?o zZeMImX-eU8gTQ)KU%W*fjn;d0^TI*rfac?^&x-yc zp49&it6NoUQrMeetk|R$_Wo+%Zg`9s3~zB;=U2`%j4ttZ$?Gs-I#FtjCV5;BC!Csm zIdwEjN2e>a&WK*xm187@s}TCRpqN)8PAJ$8&I%6T?dSkF?_4J$AleDTSMh(~R zn5AVY53qn3k^GC3RjYi;k0hk)GAxHSP{`|~KADUK@Oh9W)BZ}*NKNBO7#dfiFeR-E zTpHeHHT5CRcg#1C|>BGdN{o3P- zvy*M|mh8AeV_+P?nH@=sXw2p7P-tk>x;zz|>V#b`w#W>cqcD(kLVb=5c9Z6jx+(#Z zkUHD~hai<|IU5?NhA}_^a@$N<;i-m4e-eb4%=5~beAcf3W~1KU@8~ldEyd_&6yS?S zpXk(>l73ize20pym|58;xqF)gAN@#_G;O~7uHx`e#%2S6XOEDE|NWkQc=~GRF=sN; zK#=QgfDm^|@b?9RTjs+4^hAXy`@F$ee20R7jb|zs7zAnt+!*V5`VV+tbrOO!yH4J? z!IDrK`f}%E`z@Ttt=F%j7)wpAhWOVua#ComKm&gu9HZ1Seikd$o3=m31dT^xcr^fp zkB#NKI;v@)JGp7wCPiYD;8aueWMjLx#F-FhX7f?{FE7SC-jS4)Tqt4kDEj4MxM!;3 zlN$#c8&Z=lGl_DM(QrnYmF&6igCBJu~(zLO4y-x=^d<~|wDMAoe}OOi@GsRn@@ zH<3DRncSG-xKlydpvSF+22> zAD~D$$ng!Q!dw|qTG>ukIPG$xt7zP6;LUCyZa_#4YeoWrkfMf0TG$bW)Nc6{v4!m^ zDoGFUEiW<$Acb?|DG~2sj$g)%xsrH2oq{j|N+28yAZ*|?pF>T*h*q?I?CBX!Q%N18 zmm#+qBduy-_=rNCwv zEJOC*C)|l zNTYhadnw=pU|c9cH%%@Jub|#>%)Z~YVrl`h>^kwk@eG2)f`_{H$q{dhs_j5Fzz)DI zVevz0h+2_8fMF<;tgCC6!2Zm6!{7KQ!6A)nFb9E0Qf0(t7eAD{8&*X+rCEZw`P2t` zLnA!GC=huL-Pa=#A*+aN5&RTkz9bxr7TQ4u_0O^`d~Dy7q?m5HP>2XeiUL5%*ijT< z<_uo1)$n9=ynaSow`&$aq!0_KCjzZ<3B)n5^}}T`{!N5E&^4B<1gE_kk)BA`&P^2t z8|PvHRz+7i!v<3~!bUz6bGEk%-hV*H;(Pl$`mIl-e09Xos|RX&UO@sPhWK3Lqe%m4 zrn{$i3kBWzo_^MA0Leu+gbxMku{U)zwXs81j2mYgh1?Xe5EP;#obE=+spM7L>&6{c*XsV08?hgN`WRYE%6dsgR z*4NOpcbm&$k7+@=yB!}vCvu(Y0J}eqE(HKhT8a2qwtiE+YEd^);S>IJcixrZUxd#$<&A6nHs&TYn)Ym#s|HrAbp(&L86yjn*Eh*tO2jbW<~{=V#P0U@6S~ zq19$3)c%nejs6g0rgmJq{wRmzc)mZ!+X#emns4g!1Opp!JQ0gB(<6E?QTzNF21y;xP&y^C+HG3@qA1#MR(D zldLdB*@O`Fh2EANzYc(DG(wd@&x_z355|fY9c)}5kV#dUZXl!{>&z)GcapcrCcAO0 zn?RcULz8-i_LyVWgc_O=1*Z^Mw5Z`dbm<-HTLME2dOUO!9qkEjnqLJIqi7SUqA2qY zO;o%+wYZ>N>#5lC28GD{bzct@W#@oXXoe!+B56envk@m!UHx5dlWfGM_!H9nDUCdB z`gpA7$u^G3izLXyw%7vmz%lDhYLouJ@qMInSfCp$ZHPK0gkj#NMv=hk*v}3%1DaW^ z^bhx6dCI^zV@nn~0U|-A()@%Vhp!+0^IQ_e!ufJuO;(Jc6*Q`Gk)WXp^=)dR+nL7h zdhw;n(SYI~zbTlZS7RYGnZ^aBzvxo2;|o=a7#xdKO$)L7z=EGLn zj!92>r)^DyFN7hW`WgIP0S=sLs-*3@764o}9OLHM$jA%OnkZM7LBZ_{)w}_FCvnQMHy9(YI|DpxKa;-=BDh(Y zp>49&rmmEn*$3MEtMZVvbH_mQjW`+O7!PANh>@H$y{4HEH8i8{q3Q>)#$(e>!J->o zl46`6{+%bIYjf&3NUXXryyEQFG=;Hk*!b_(*sekID9#5U&44pp?k!DP#4@zdSj~)N z%6SwHs2rz!0K#5m5NbQ?vy5QGNGE3*`8lmVN+wZEp2mwa4;KS@&u_fnZUHU?&vr-QeLCi)V zavkyju|UcR?`5BzW;Tgdmf+UiUG7a$8?FD5@*r?cP0X4)MVtY=cVBF6wHQ#l-6e?x zpNa6}Mz?4etzAC2Q&ijr9Q7&(Ed3v_t_qH`v?Pp)l)D2cAx<_%RL+~Xpy>N5mYL_D+2NWi+bPeAB$a&uG$z9lxYLOIYF6O zDEQ=zoB_LuWmQl?a8|W1lA`mQWw0|+{z+00Y&cm{2s31@KTOkX=mR9!YhPbU?e5QO zh}#UF+1Z?4g5{*T>N?@J>0~?X$O9&aGngbwnk&x6);X@)$PS#T^(_7gMOm)<4O!n) zEvJ?=77p-drW;u{Y#9!AA5)#mOw;iC!GLo+}8AwtN7ZXDQj!;*LyJC{R3UwSvz-Lp)2^`p&8lBkQUuE0j$#ayEI=0@QZjw z?nv%c)qMCAgPlZ$<+`oz?WLndd2&xIb+O`fMTr`st;uu)q zS6^~6QCzt07|$mV<$FwA`;yXMk-UMamB z9HpxuR|+4qBjRy+MbEbfe<2$EzE}nJm9FJ8J*R|4+(@4W5YkpuR-*pa5_`sP2G~5w zWp&T;Ft%KIOz6s!VrSsC^%=6;j#CMu(v*7do*Q12_?cb=`FxRiVux(e8C%6Ab70q|@MWDBRJp$5U^ND~R`7SN=}Xuhfzzuu1W^<_LholGnZz9yyIR3qyPJ0@%tm_bxPTjw5EIK7M~(?OQ`0Cv`GWNI%e5r{l&n78zUaz75(nRH ze7`ja(VvrNv#X2`YQ;}b2w$$9j77^Xbb9+&W_728raZ0|k3-}YPQi9Q!jxBfJm0-I zB4&hc$m)TNNX~?(&GXsNrwr2rMZYjgG&H7sdKeyGH`r&09Y{Gd@yAOr-8Yh+;l22r zz!mHz_4dB|iTp}klExtiFyQA;ivFT(l%c(pskZd@TSr*(LF`pW^o-j1gTwYad`3c- z_&l8ZHm@CqT)=13kB~^-)^j#t1B+T)iJ;FIsI`qVN>l9JY0tuZS%Ha8b_-b_(7o2R zJEuffHheDeYq|N^g~I`s15J5T)x+E6%7klbVU^DAAyN>0H|^ zkYn~pB&4m#^1Gs9c=~x0Yp=jCnk(YIGW7)e^NnkkS{DWiRu~91qcbBK*7O^@S-w@l zJx<3v20P+wClRUkQ)fc%87bQLh<4D~-kqM7LcGO6O1i9DyeXB}qC`sXvYX$>6cn2@MY>OpG0Uo6IiG4>!tCxAhZbN!4)^qNu&^d;7Bn22~8}NRS8~+CvFy{ ziHg@1_m5gP>_!sZGvfDEY~}Luf!Fl?K7#Zx11cNdD`kG_%a%-Ok2~p8wSFlpqWNx!xl&jIUQ>2-=UG`2)%6PV_^XiO% z%8w~STath8vmfyR+m->`-AA`Acchz}Q|7oa@ItY0J2E0Ztr}nT-EPdoOqcOyq`B0y zydNDf9>!ZAeU%wHIw65OS8FalR+A|$zHUG^1XxijmiU4vq?0fsiznh^uvp93(_V#i z8&zNH!z`@jWv2-#K*oaf>7F)2mCi2drJHYQyLCut zw`ZA7WlQJUJBFWudWr&CF#nCrR)>U%BF2Bs3t;(-N^=6U4g(;tL5r_eCy)MkXF8J~ zZ!ozRMhwKUOq!)6S}9D%SeU12e;AFV@*?8^Zg^gp2l z1D)j7W#8*hZjm|-*T}cvq8sJemU7W&Drts5bwj0G2y3Wzmnta|Ec-=xjO1bh*OIiH z%w1?KLeds?sD4$D0?cs=Z;tpN_2k52Yryv-?Zi&2<c2s8f&JEqk=(0mO?_6J{IX9VQX`Qb9RMWtt(1v(wV<7&T?N@SR45iSl;l({8kahx-Iq8e4dYLE7Zl zYfygo%A2Z|8iBy&bZ{myj$ecf4Xh#Was`*VR>k(5Q%0+`D4p_x2seMI)o!x^GmV%C zcwa9=q9U4E)RVBLjX761{*=n)Uydy~`uV!Z2zl09Wm6kvt-Tv6b`>YF#d&yfIa$t9 z{1vIWD4xCkEP<$u(<$$0r@iy?O=`QO=h}s1_>uLy~YXfjk`#s{~=X^)A;;g;u0XIue4`E}LLMzfVI#?O=8jiBgdz~~{C=chgseu}RJdaR$MG;eam25zZ!MOC-e%CrM(8RQaMZkcI=#!#J=4h`ZT7Av z7M+)fkDc5QJ8D`@NwS+iiD~}BffTqH7f;$gdzix8)HUxQq-VuG;wcy_eI^n8c^ym^y{Hs1B(-7#kFWZ;>$%m^yR+8W+4pHB3vsphj3OeFSn57#SkYbFP8WDt( z9g#Mwf*hY63HXI}x{v04`T-_M&VB&95Ku${%ind{27P#ftYyI&_$QD1{diYgB^waU z=aR={e$~;-|I(@k9EzE=*M#3;$0b$VQ zUzswpPF)wNl$;Dsi;lcYE^3Qxw+*km%ExwC;R(?$I+w5MTu+X8$H1AvVrwY_s<=yqmR_kC;E%M|0N7xE*&4) z#LBwYWKBkEy!N5}j3g(Jr#(Mi0YFK(JhKcF%#sNTHS@XVHg@N@^9LY8A+crc!a(0K zV5$yA{K38(K}ht#ZJ_NpHg>HZ^Dqs**lA9_rP6L*vNv!duR*4eXvUnW2D1#C3X_ z?BTfSw#261w{+BUxjIgPh&g~&SPK}I+)MKJO%I8MRuw6>8FOLGYHV?cIP5cW>TR1M zDav#OdZK#m&Bnr#kj>^}>p-BwFK zSm8WWO0#`>y<;w%vHQoi~-i}K9s$G17OcJ+cK7?TmKbBl0Hj~^F-CR@* z+z@t{*7N>uV)#_hYkVz|?9W5JE<7xRW`5GEtNKv}vjM|>0M=fTnEkH3VQ!DSB$CA{ zaY-N#?mMJvRkSb%oNdI_F_qx50YP`Y?k-Wc!4)3Mt{p@>j>DieuYNi_uv}Mw8F#_% z4_Bz3oxxF56B-;f*gc;p7trX|y zfXuhVCtWY9kRdmNuBFR&o^v}@<_78Gs7}(n0vp3l_G#d*!8VOk7BNAumu=#4G6NF&Ml0xfk zL+LE0Hs;2dDkKlvp{MGj`iPKZVy@H3eDwvg?W0A`uJWF;t#$Num2~%vw?j0wHSPK= zAK9+NizjWI5mfL7V-M+H);mpAODgX+C7gtO>5D4sp_cuGKR(=We}{wPfcT>g7n*K5 zP{Ok5QB?z|S@OnIDHsR^u0*XSGq6KDu217#PyrF!7$GweqTUY4u^2etJzwglztGn^ z7hTxp)o0iM760qdEiAaVuPsTTf*O6&+zx2xy)bpb!wG}xGaMe$E+p=s%1Mygb{ih~ zsL>RVG3w>f9t!E0=pB3Hr&j%kX+HP>xLdU_52JA^`>Fy+SFE`(w!PiM6^0_SHK=sUhaU{F44tBJ>I*}V$#*#+A~(NU)k8Gbl^eZfK0b;dq)zkD zf*wD#PL6}<(%bjtp`7ud7hoa0!NwdXn^Ex%GkOSr(cDy*r z(FE+N!fsE#STnKj)L&j~GbK78o?Q^~He)n^9&yg|H_(%tk2E$;Ig zdlvXu3*6s@qvfxl?vf^blCTU(HbhaAkqo&j2uT*y93&LYQxKrFx%j#bK5pn1c*s&L6QmQCKXJeRc?};} zR-bHP3&#t=mUCYuWhMbp4s_eY_l8%V;S*q>r|t+%fql2hzxvJ@bf5v+K)%)$>)mA? zFGl=g&(pYG4XT#R3kE5_!TazL+#_{CUNfUu@fNC!PbsoK+i$|74Fm1N3^I^kapyUI zH|uQCPGI@8)hMCEL=GdVW5#-WH=~(=BO@>vG;!cz24rG@b(6cVQ-RTImi(LZNH<6{H*pD3X6k}` z{S0ZzTxT`>5dcm0D2Z;3HLDqSd=a#>4&i0O0l@+B!=fTXbNcMcM(85?U;bGUb=#eN zFYFL%kh^QSxc)t}tmsrhr3vwyHpNz>Yd+h6EKtdJH(o00VeoIZBpZK|lD=Ae$^!9L z8PEENmJO5H$ZXKBvkiT8Z3Ec~q}9jaDbO3K#Ovh12o0b-fohA( z^23j>C23nDD3P0(R%}uRqC@3_?h2`5sjY7Ihi@@_tB9KYeSAG8SN;cKRi56{i6b<7sC=%pU@ebrwFp0^jO6xJ!=rMjU5%Xb*|x{QaA=hpM$wFuf+ zii8Qt9NcJCAyqtr@-McaO&5?fjb`&}RfKc_f=S@q1@sEA)#$zD56VU-ju#Bl780Xnnh6_XBnm4_H+oOFOZcLH>?X6C5$RX&EtgQ0RFPaXAr~B zdFU7L6F4YHMumTqMSX94BLCu(h6RI-hg`E7ujIXwG<>;4i(#>m)@K$M0-) z>fh7gz$wbZw<$SH-AemXH8|NTtv!ME(4m`RkNex%_HyFz8?&OKMkJ=dlm}1j;sdK9 zOB;@}s4=9=f)Ztv?;OOQ>=B83f7lJ*Y6j?3IAceTSvKYJS@OuvS6|be*YKJ-p z5(h*vk0B2|t=lEa;BsbG%{ved56vf^WMfaXtC}bDJ4m7TbU&?O)}=Gj^&r91H;LD2 z!KT69?^4m?UQdS=+N6Rtu59VD-V&JFKDhXp_z@{zU*6h;M@O}^%y~BG68oG9?H-p} zJkuFC2V;B-!t~{=PzM^M1&KLKJaC;rsmm4yk6M~dzil1zOz8Ecgf&SGm+`opL-yX1 z_^>HRBHHsvIl`PB9Tvfc$NgTods4^%6LdLU7Qb{SFA!x!b@d?Q&Iqn4y4#O7tO_vX z=1YM1$$o>|H0EB0v*Ka_%qL)ZOwz`82Kr{J$U}H#$@9e!=$6TsN|qad*r2kyrBi8z0i72 zLJvBRP@&3zWEsUpr&*&KwmlmTMbb^#BFp33<8}BOu;?^XdGbg*i0dJ*efuxLPQ*JI z)tXCq-+W2~261GfFJwZ%%W&})#e^-(=e3wS2=79wfz53J=;XHQtlGyUJ6+@CxMaRG zZx(nPSwiOB_ewwJ)dOZjCi^^LdROshGJSjM zL1{F4dli|VVEIEn8@VVK#bwLcTYWuwoNJGNM2?fuX8(JQIlfL?9!sBNbjH=K)&NCZ z1x^iO0X_Z^L;JvI zZ7){cqvjv`apNu4LqNCnBar1K;3%vS+?K6ORKVJu)T+!$MDGHR#z(TDmdhFgn@)`O z{<`2aw(U$=xjH7q&mRfEZZONmREe$vBTgu76Q7mbvm1)skR)5UKWpOHmeNA0Fp$B~ z(|C$d7L~itn+%U)Hd_Kt*KT`jXMnA;hBFeRMeHO#V;u;&3MDh` znta@hA70?GRXz@k{}I<$`$XENBCGxkkUKel*P<(fw{kBRg28t1)&4hUgHnSgy>M$c zKD|=S=fnUS>5bPfK?;w3uKU)BAFl+JSZrX?gMY1WdL}u#!i7jtN<1~7hRQWL=)@Xz z1>OkHrpN@m!*yM0vE!Oik2I1!k$5NK?Vj<~u+Gu%O-61Oedt~K-qAXG6IlOemkGuI z7dh$YGG4Q>ABS5Z8SS9yYz|(I({vLSHK@5>OK-y`=Dh&Uwq<2DEq?!x1_3@J zL&uzFmQR1d0-9s6iznlQjZ%)V^GZ}ydGS^mOWu9$M{C0?>hA31sZHlFJnAz*+4*~= zPg|wuar9ciXXUkGsg_A`i}wZixE&^}TfSt$J*yJA{Nq|h*7dx)N{;zuQQ=qVK}xjv z^^lS4>7=o$#-rpoG2<)hx>>L zb(vD6|0wTdz4P)TW($cdHzc=$hpMsb_8+fBLerUU{C27UA=&HHb|0uulXkX2{lb%9 z{UBFCL~lR;^Brz_hmHfpUxFn!8NJ2fEWLC5neQlhY?GUCKBo#fpN(tQ*UuKDP`8E! z*q?fFqE6F&Y^4!=)4NiTUYeB%aqe{I>NAi@^hWP{bw!{C*^HL*3%>tH@?*Sfy2{kv zX7A5abS=F*UOUbqaR=mrlVvnC=E{?DA|Tsh5$GnxBocqmy zF^*ECl2f_ZrC7M5%>&{neR963045l#Q*yU86ztMPfGm!!MXr;2b-fBLmF_Tj76+jC zX0ya$&fETU34wcSw7AUw%Hr1wp&MSyLc_CiE>?Kn3lU& z5CUC?#} zC7BX@44M}Ox{2q-DbQUHQT6|8|DMZL@TT9T=iE__3d}B-#q~coL1}zSo-ATRQtIdQ zpIp z2>IbXL|dh9$NxjoDlT*4Dq^GCy>V$j1Zu`;vD^{2h@l1&v6SKcC73wTRsVcHnbuTB zU9ww=7Z0Dvgf}<=8EUGpAwoZTNqantF1*1IDWkhdAGy9JU{0Sd`7OYM_NM#WC}0f3 z%lnObMCuFJSK)FePCUo42qy!Iwjwo1)8g0C&0>?k*kh4h@!zLY#1LPan~5t+V{#h? zt!mslvE^bJ85@3MXgHKa_R36PFE73O3#VF!07yR1`saCxBabSaO3xJ60|N8 zXM)^_ctdJsfR{M9MBYX^H@!6j{nHyGFg=v39Zik{TMSEo=3>cP zCD~ z+oF0cFnIqni|Du<_TRWJKG`>Mns*#3P?EwYy1&&1Uvgco;Yjp#occxnA#Xz*C z&40PK_01#7bK;`T;(bX9dxl{3Rp#+UXK!rfZXR6vrhm4lzVqr8-2aC4bglB@>&LLX zTq5`1Sv3}$M<2|^wWV)C*+ckS+?X1}FmJG9>|z%!oY;(_?@dW@ zPU8Lkqe1r31wm1ib|>kpxPl|`2$g@mZ*aFH7owZZB|lo8ifJ5>T|>6)is)z(MUs*= zc`PrUOemLV7_mt47hmjb`#jg_mNi1PSc%f{KfY4E7aI2Ze)4XP_6+kGhX)Uhl#I5I zpuXd2HmaPT3zwC3QmZc*gyz+3XKRzf?Pi&s2VZXzf5Sl!7uD zhihedUm+-pLg9r(%fcuC+n)CC_;MQB7e)Eno?mt+c^ug?+dP)Jq=H(Vh0543oJ{lt$C-uDjYYQe~V8N|^ zxZC@{e&*!(c83YHN$=L7I8TH+>fC`{k3-7_f{!7tGb0Jxk(%*uT{1?T?IN2khIJ#B z<>C}v8)(SDY;a3pa>$jv4YsVr6juh&kNn>%JS;F?>sucWJXMue&AB^`*)aNZMw?c4 z!o^V54+4}n%LX?*GynD(WNK?(7vHt=doXZ9bsFbKcug0Kj%DWgmHh26=7d=%SH}~; zFDf>(!qTBkbi5*!NFVnOTKoFv(o)w34ZR#Wn*dYJt5UVncd73cslf(7WfN4ns?qO0 z(%b6pLxGUi1n%mVCx>bkqdM;}>AYTn&JYM2?nK}HrSJI)VF-r#MUKlL(&G+?*kVT1 zhj8$T$X)Yy?a$3D&Zc=Y;>7IzsaX}A3|*`eXiZ+ev|qCsdT1P;;&1P*Nk$*av_Li0 z28-Cv$WyI7J7OGa_P-N{6{htJYS!I&<|`^{6|se|mQO4P_YBriuf)bFvL@?(u0~F_SuHBK+%%dHcsj=#Poh4mkQ6h**m*Mw!4HW@fPYD?V zh4EB#cHyKv>vZ<4;y`U5zSJb65$V|^vD>#sK18@t2_NJ)gAt1)Fx#3Wbq=zXfr)!! zxEncv_j$HM;Va7EPlJwGSWB|JrTVx?n)~0=9hx#dO(Dz`9QV%1!UZtQaIlCzm_u2J zumv*}4mO+uzq(qZ+=d|FY!5ED{e|aCdPej={AoYZy`^8q%}`HHA-pC*Y^tkrPSXX@ zH3S&et@>%;Wo6`-wegJ?Tb|WG{eW$r z#O%Bcb4|VYR>^sFxOrPODiTR;6$r7w;67_#pnJPY9ofEv8!X;J^>}pOzER$8wsJ;} zJn3nTrOWL;x!npM@D}fM7_spxBiXv{+JN>is!B&116V%MqOU3c!X(J+U-@ON{%2j$$>}% zyrjDre!>uPl|ldc?RCHRxAP_`L|@d4@DAiR6Y{M(*vqdlU&Tf52G`cz;Q5oozCW>{ z0oR$TWa|v4>e@9IH)mQ*H%VszzkM)l9Mqc{^B+ir{UA;_wtNXlF{fG>!VTc7g7f6( zzteXRr}dvcg5QjJ*5B9);QFQueEfwew`2f4K*GO?y7?cC`2#!D32nq`QMsk=5WCyX z{pv`tQOs^;JBN*OX22x!(=a^z8G$&R77gkp+79Vfd>`dO7dYrP^?L>NP5op%BIAv; z77K|zhKQZxmJPY8KZ9#jn^lAf4xGqom&5~)e;&y_iae-^n9XT)_V|~dIbvISUw>Y! zEWlErz2)4UGO>ix%BdcKz=CbeVAM82LCto{D-WjVWRdLf3-X0Kq4!|r_6VO~+e)Ob z`C|3bz6Ozn<;7XB3Wxn`1u@6UmAC6cz+;!%{K|Q({VW(sIH64UGqJw_bnQ8-s56 zmciQhm}&|3v-D$7M5F7FTKDOjV>Wlmj%aG>{#Lx}l3afDw06+IB+sq4ok^!qMRfxm zZo5O-d`5Loi@%*8OL}&kbo+y34mXCokqiJNfp}J;5KqWZ-X^bjl!K>$-sScXCLrL{naBATxffg(cx%Z2eXaJ5<9(E4_ctAxm!_;vU^&i2aMgf7nmw2X zNv?0@xiYu+1#)4H8Uy%baB)WZFk7-D5K0OP7Q zG*o=Q+0SvCzn7Tk2~k_dyVmoCBIpPp)rU;cd9}NU zGi5p}W5J99Q+gDVvjD~0aO5g!A-{j*brj?R95@%g5ET}f?m4Va2Pf! zul=35@z0OP^Sm>|e*sUzD;V33bY2;B%E19{9CUQfLMs|qsx945#m9@{z;zq}w61H$ zK(4d?B>f`rcqvS$Ae4(ZkOmk52DH3T|8bWZA7;zk?-tSsniQWazWb>t&zg6h4}{L2~qJR3rJOw|y&(;v$sR zj94`!)kbbF2?d@Y7kD`burowM?c`55iX2}6!nU`k31$1DnjpD= zKsidCljwXiuWj_?ZRG>xT^b?KNIN48(HQqG%V;gT0*gK2#ZNO^k-@U+)zHch{|zM$ zwFJ9H3h$u#=qJ$|kZDXsfO_g^Sun6}i3|*{>lo1C=(I?6A~uf{>C`%VnLmGYUhB^E z`LQ#|;sE2_fQ6TddQTvbz-_hkH!G72Lni`-wgpOT=ad!`QzuU1fn>Y4Ts zCGFJ?$+gl@Je&xjzWOp4)TL5i;ShJNoOvQ{M$5$y;Wu1IbNLVuJM=$@ZIja1_yqs; z{zoKyxH;k_9f4ha`Nkzg|2#hav`cQGcJIWXCCITI+YD%vA6PFBYbbz`ytH;LP|N@znr~O&W>(rMv<9x0(Cx$oxShcfDB}5!*6Y$vK;<`hbN}ZDuRY(co$Q9)_2H z>cYSQpov)?LZ$bZY0u%^GBISX^o{`izdJIoVZO^g6XBV}tlgTQTFxYzgfJ!CqGTs6X}xr~ zFyKie_6@p$Cm6+8;D#BU(E!A{T}{UNT1eKGc+qeVX7X;WSZ}gxvv+`}RsFLyTdEzu zvgBW581Gf7u%|8$F(5q0cyn%XgoM+UOrPa%ou-K`QFgX6g-9?|!RjNmz1bs%!R`eR zZpr<*mQovFMe4;guhXn6c@~2>X?H5v-hh641T4?F?O=&u*!wsb7{CiYk7^psvR^4C zJqt)8<(CxDT`p<9?qUI>FyIJj{}f9hA5%6#p4l%NiQ+DB>t{#I3{mLC9WgHoF>ov# zUrcfQvMnyft+DdK-D=U5xFtuzmWST&Vnfv^UP@CiGjGm>e{Ch}sH8e4>VDD7T0o72 zJ08Om(~wD?gp7zdZb=zY4KWn+0h+DP_NMvh%lUVrDe%nHlcV(5ZfpUtW-2628EUqu z-_qYF+dUVMlsi6ZY9SwAyM4tG#^!>A7ev5Z=uoHBpOD=2KJhPq5D@c^gb=aMVLAD) z*#BR9@n@DnBe_gFZe%ent}q)fy~6^K%;%xYc8XMM6DBbu4I8NDF1#a4YxirOSi)-F zxG7wP6v-B49pktEF5r`eJ)Rrd|7&=y!(koQ+6`T`SH|_?;3G|!EtGcEWDJSM&a*`9 zE{G=43?arphbj}Ky4KkV1sv;mniJG4UJy)*1sv#T2a(`d)H!NY*cPp%T{&8+oFJQq z9ZkNW(xkx6@VV~$`!TG5noOi3mkIB(+0U+)l z^){DOD^Bkdp(}OO{U&OoR8jW`J@*eCMr$kqCRd@WwKuYlG=n~3)x3Kx!UrtFj&XN>AM9gLyZgNkm>F}oV-wp`a>!;v|kTQ&uhaJiDq1=FjD z&E}a+x@{7MfW;;BCBe7<_tTp5eY<ub4rnQ^L_>!o2kvmO1bHhsu{PDR9Bfz_w-DyBN1A;Ms9DxWmVtN#E zerpa8(3>jV$A*t#XOnoe&(kFx>UkP<&xf^xVdr461Z8JY_JhdAw*Rd@mNxiE6?6n> zze^?ey1sHW!M+pNRmn_Q>wSK0n?b?}Q7J`&Bi}iuXd^8kQ+EUch}DaZ5@mniuk9zZ zew$m<95pEI5a5dKvq>a%^qB7cgB}!Z2zYfR96$$o9}1;~c`Y zRC1crf-x*I{Bvz0Bd#^(+7NtvZ#!gO`!!H*g+~Gi;$0MGQbgT-FH@Xi*m+rMhsYGI zWD3E7bb}%h;rGvJw7eDgbv{g?6xv&Gj$8&dj2Wn<0cICHgQlh)#6E#1kb)Z%!$Q;laNZ=-nLgRyz@~gu+xPI)!GgHeNG!8ckt+ z+Bty}yoO{DvBPD-H(>E4=ENfCt2nm>A|Av-rhi@LOr3=_RDFq{IGGBga`SAwvCeDt zhWyc5$;|$#Ov2R?a+m6nO|4_X$0k&g8;I(b!_?ucBVSYS&ff)H;~)WsITfYUm{065`D-rVxN6eu z5ZNVEw3JZBdrwO|mAT81yl0*4N^Ii#g|Tw#0N&f!0PEiti}@~4z#J{hGU+|70@%U$LlDJ`KnAzbZBNM6h67jrgYH41QtHQfpt1i;|M zCstEdgnZ6VKd9jVH={Gk#QHJpf;zmqt$Tl8cS?%7%KxPA2yz=ZMpJawwC8Qum;NxB zfHEJsgF-P*csr;5{pqrQ#=&701v{_;kL$KCv{kgoy304RpX&L}5)FDl5?RFCjw4Od zQM*2fB4tdqIM*{L!S3IZSPh%DcM*n7^Z;mknBWf+%N2s#D9WVd#R%V8Q{jS$y%+!Wb`2SyAl1N$_#^-ID4#y!vF)_1EMR#x12m|=o`(~G}JnL(3 zM$?$X#ZFF4<*VgTwx^8eU69sMb2_bv1f=hWos;B2x_Tr>fNxOg4(HNDi&E}J7Cup@ zdG{q%$wzjLO%wgcb01?RTR1|NNhQ-`j)LLr_C8KPIOp#TqQKRH_W$f+v=e(WUXQY~ zp_EP&xdx#`E-_AI$}#Vm{-E&})rAlB|CEOIdaxQ^PaP`$?+b{q@2V&TL{d3pwa%tR z;xfM61(e>sc>1RkGYs=CQ)*WsDnd zC`@=Q{%s+^g?wwsjW-&1zG<;H*%T=p+CJ;_U7h?>j0v;WpDIKrt^5KW2v!_Ir4%i8 z6#;g|&lj~;G=KH@yU;%jEp}~(DlCj~o|-D%#LLQbD*w~}qaZ$Ux(8_)4iRBx6frcU zb*E1c!@_T0A=kU}jd_6*&hJfU8FUx;IAMtlWz{qQNtvIT9_Nd#)XMNvTbLw`4s_#* zjzFU=`4Vgzd-czHY1={EQL0NxHJwSxF~GZGYs42yKb~YVg=w>E)>gF=-E$wUt9IVd z$M@eq(_HB3^>GQEW0C2mN+_}S(wiGAiIqkIA^EQZ4hrKIapM^u(gTv>rJIU{tpS&GGaoULCeR2@_E5ST z*-F7yElYGX3AgyVH)G0Ri9mkde_kgqZ)vHipI}@0XO`U@4v6N93{kCYWRq_tf$xK2 zc6%tw#wa;d=7TzOrz$dw}*=1@S8p5NO zYCBw;9@f_c`EHj12yBk^N({?+C}-oiBjvW{K9=-9jbQBXYAbt-efBz%y8t3lX6gcs z5vMX;6mIS0Xs#Fup>w+xG;6;MLK!SSWHCqi9}&r{0LllJ`2=J~qbp-@I9 zK@HyKt7ZYv6D=yI0}g#jgo9>YBYL%u{jG>>p8Wr9<@aqOJ)Jz}#p=s7txqIoK>%t0yKr9U-56$flM`!{8o;B(4_YE~zn6hvK=g!# zLXhnJJuZV6a&3nJf2e;}eAQNHk^a<&~2kIC{2m@He>f-`_< zOFt{0a2k&XdNkD{MO3?J3NE&n{!mAZ7^^|9H>^-GzLj8Qm?Q0^j7B8GOu3(dToXB= z9?;CqZu`X?>Cf5LD%Erlq`wx<1zX7iGcPkZWDa%UR-HzkT`}a2PjDX0*A`I|jzLqqqN-In<`rWiJn;7( zxv5R!-I~Pha#J)PD)BH93q=rrgj~8wUh-j*PL8AzrU)#2$>Tu2GR<>gtQaY7O^q<1 zgjRA5;8;v>Df=bIRSBe3(998j*o&A#&Ct2$po$p=yFD%T$9*8@g5fk_Iaiq@7T{5k z$hi2e=h`iMk;1LRX9o!KLUdy}(^t_@KBVS!_G$XKkYnl}n1b(+eHrfoHUCbr(NK4< zI>53X?<&M$+h3a+m`-sxd;msTgA%*Qa9pKj_v%y|huueYIhtoJMa(HMoA7mOyxQV1 zG#{#oU8dL`&BmM-s2RW{aZiGZA&E%SH8MPK-|C%0aOZGgZcQl#Qy*bdsf9uyN`d7 zgAMG5Xp&s9>+aaH0~m_mqh; zb>ZZ&2eIoA*Y1=^#a#; z?pijFX}ANgwNKjX$09oS{vN?&2h8zA0V17!_gRIG(B4aREwzhJU|n)tRG`Ifq%2HD znA%Zy!=SPkuJ#EhuamkTcJYW1`d0C{4ZIrJ<@iYl$!#pFZn?e<^T}QARM%^dSpvq` z2q*qChC6Q&DbEy9To?4S5^p#LhU2wIS>VTRN3n{D=8 zJ9BORq`dFe2MUrYzdudqlI$Nz$ajz(ykV_m+{lAy>{~`gdZ@ z{yXnZ=RB#$gf}keAF_aG=dPhZVwqndn$+IEt^F;XZ-n4X8l)k)r2T`3h`tZ&4FH1E z3UiY~R$LDtX(lm?7P{?I&LjW75ih)|_P$2`XX;-kE&IJHX>gp^kw~_RR8d6pKyP3s zyz|&QnCWL+!;Vx?hfw%vS5o-VKq?!)VFv_pcgV<6v7i2h^CyHX2jD=9D-Ip)DVRNsu^pn{;#2L;61XiQD|ChQ5+!1sF z0lELX{W4`W0thjHR;rp*`sb^pzwCC7m!N+9D?;R0EeJlRJ{<@gnTBzz0^-uiz~cAF z6yqQmSO4~03u8}H*c816P`V|B0U&jf-Ri!+F@LMtB2sE95f>yVs-fi{&u7-KF5RMr z=eY&z#+ED2#hY7g|0Y}0VJ5PIe3UYRim0AAX&0A}jxwL>_B{NIo?Q^G8YDA%%jHnC zg1o&Szl*$9Q|wbpDwJ1^aF^Pl*3Itn%E$Su;OSCw1_{}JM>Zf9S$f;e@epX4(X`o9 z2344lIf6|7D-uP(UE;~tUN8sUA(tUx>G^tU0H0X#b*-Dl!>Lt)IzaI_7ZkFIcK1p9cyg=GOi;>;uBbcUE@v1(?!9bK zGt;)bVI8Q6>4BxJcrPUtWR~rf_i_e8v2Jdlxc??kr-8gy)e;@h4wL{G=2PxtN>p99 zG9ttfc(k(p*}*Y#R|UrN^gIswDd;H`Z^#Mj{aMeUP0sz@-HTj}qn~caQB(=q-+Xj& zjJBesM5N&UvX8AmFrQsPC3^LhKWX}#4?7EfG#H^7oMsU)@ItGmSQHw7)tuk>4f+VT zv!}`xXBz)?;9>cMXqgA?fH?I4n zvC0yg{(Pt`kv9;@LMD(s8&ou0>mpJj;m%#J$++E(R;>t2L5bv2yTqUn}ZWXiGg zZd(6|Brxn?+h>-BxgYNL-Wc|QriCNPESj)3xei(y+Jg`i`&bX}J*a(1r`pOIn zZo|C}C2`bw=ow&OvyaP+xj{_kmZ^-?FgITPZ-51&syS(`TIvOMFBpgt4ci>NW2|ED zlWVW`M0N_YmGA;atizhVY4`Ic8LQ;(Y9)+wSDRzEf3U6g{i{&0Mkmws!!-*5cJl>6;VDkvETA99CrIl7|>k1&R4>TuA_n z0f9x_bNVKq&^x$<9TTD|t&Dgr%E&#Ui4y7HW<}FM2JHe=(%r_)=~3I9$rwr^$5mpe z2zAUlkr+oMju@gB%BnrDEKhfefWtJu`o8*!Sj=$wcfDo;C<)lQ;A%D&}4 zGi!t|+xvMv7he_+CyPsF4G7*TdBMDVSNV%*h*6%8)S8hR$vNUg{}>}K-4`CHY}Dh4 zWn@&bVNsa$j60|n-3_ii^e2^U6eI^7$?>?tOLchOlD>j2Q*2(`e8k|M5CL!4Tvr*)H0XO+*co@B02cXa2>l3sZt)vTbtzY}bKhRO#N`~*PBF=V;7 zV>ONDD`IEDv;6n^EsCvvNGaW$4?U3+wl)f8+$e6kc7TJb=CC(OlT3DBtu{n@)@e1X?dsi6 z6h1mLyM|U!&98@=ZTf+Na&sNl0a=#U^|T*a;By4~MGD4mEkr+`B6{TPVAyi?BOi5V zZp3~F9u1+#k`vMRG+VlGF=ho-@al9PSd<%B8CoNXr1SF*`M)eel;$B6p z2(dmaq|TW$0AKne4?XtKVuXQ3+1&?bho(xSWTxBTQdH&>SwAH>q}b)xC#~t@cEC4} zNfVuZW(?s*X^n1>>7Q^sNCJ{Ye<-CI1Xs1FQ=UVwZuo9zU!+7?ad>!hYB3-1g-=g& z87&u}uT@9j(k7Cjy zmnVySi0uzRa*^HkR8p&`}=7l zP^1o?N`R5k_{Zi}*rg z5Ox3u*##u(JBRf{*5sZvjv$nHtr@CC@BdlS!+}^BN!E@^UICPY!GT%h}g`d6E|o0!{r{&3%63l4}-bPks+X@YbWwo3e_prpcD zd(1AT+xe98qC-CD=XBb*kT210Xzh$sWJDdOEgbp)_fp zA;c6wGA5c`hh!PTE;SVnGnJmC&^l{*c^HD*V_5_V> z?MF}1XrgS_c6sMMAbMAT&n(N8OVt8?qJ5v$MW$OmE&Y^t>E@M+@93-)clL%io56+% zt;ei(O?aJ`(-AJ6U!9dmm<|ggL2ohcjMjSWww0u?4$Irs>IlOO)Ppg~XWrmTz_yS~ zuOE>Q47cKKyP+`Ug_|S(g}QNl(iehNd_pxKK{D`^JMlQ!gRa5(z$_&SA81n7s33B+ z$M`{->9g*LY$nhGX^wWA^`J7h=Ya$>Y_?kYf!!=%2qV;xGKKYSPJxZyB4Dvv&#u9b z*K+(@DiPCT2po&7IOg&g&@MrAXSe(=1Ehq!NtqKUQY~ua)1Qvn?0?x(;YAGT@SVV^ zlrVZu-7F8+qFxrUTFn6#>p3#h6wZB3|(N#V=*a zUr5n#XCTL@2&ChiIjL39eZ(knPziGpRoch^iDkNd#efWH7lP+gT8 z!8_0}lxf7!>L=V|Vdxn4Ufugb^l7lK3RoeNd+mgWbF0AQX}bZA(crA3{~B{3poSnH z#?1T{#?q@e#^yhIi}*skxXBB0>Z)9J#<`$?6g`><`>Jr}gFn2oCcFXLwSjrY1NtnvTGVTn>5qQEv2U=* zYA5H$aUn8fwGUVtt2ZW#p_xizps=TkoIH2>lfHST0y;n)AH6innM6h(Qph(29mE2( z+KG35sddF)WQI;$7CG_k_|Wd0>&T8;l|D5mGTS$vD)pIKZ)@KO<@0s)tYtQ1ktv2q zOx&wiF=+%GjSL@bDuU`BTK!PMAzx-8rHz2H9e|fGzeC?kI!ib3*yc?Ye?NdRR0kL1kC!2;Qh6=~8Rn}Qy3dA^bUA8x? zE(k^k56?K88YTUU`-`l=+DL71o9qfK4-Gx{1T^PdYw2w@pSVQd>?O#+tXOxHTls!z z<0QTu0+}QhVNE7Y#jfpUU&25#&r56R`=jYt{mw$duww(FJ@aHZITfHbv|Gq{WEXys zdey=sSS2)MmH2YU=19F#sdB_Zk#Ly7Z3fQ*86xq<80qJF6$T0g=9qzgdQp}CuQPYT zLMn$Je?Vq-dTZ3wfqxV~S+CKHbj=-z$H5uPzU7PPGv5XUjYbJZmPTnq=zTzfMg*{1 z@20Q)t8BKzIYsV+Z_+qWo}-lHBIklNrm8q2*CeD}9^VthD4Bq`m|ZTzzY#P}i_GWG z;K1l};Wt!^44s+_kx=z%?sScL^pTrA&d@>_8f_FOatKKBQyQg#a2guEl!%Ag! zS~CW3E!{|AcJsH`78N!ILb~4HrGA}1nRd0L!0&+{Kl(5aaHG=J=2L&88&8aV1$s8n z>IETD7yU1qv^P{h9qUs*U|TxHlMnmSWyUf?&{;DBXh0i$dM;)*yy$YA4|%1Y@UcBh zM!a$rjqlqMLV7f$Ob$CuS=klb=sHw{DA)`(x>v|A|I3f4wA$^mP9A_r1*g=z zmaZeaNL3hh9S}G`iOOJ|)x=T6$U8*tui2IB`?&~D+Q}X;iU27NJX~B4{H#jISN|OhY413gc#8OE+X~wEkft6Qg>_14x|#uaY}%8 zK=&@)2J=k&z;oPUP%c=x2JLvIa$b{zDEj4j9mtaXiGSeKyYiYC#{<7%AtJl@)SMvd z%&}SzRf#9yJd_PSc3&s212R)76`Gjb0M+g~P6EU6$8ubPP4J?Kaq{5s@n zM>=PJu}`BTf-9%h-Sz57yNW22Oh)OK-vBy$cz=fOJ%8y%YAl#}(6uI_*2=9POaTmzN2uuY*Pmx^&&{ea9F^XD(UFi;$$*QL4%kHb(JtLjA(&LwTam z@9O|v!zOYWY!39{txt-X-budU22|!?Zo^kX=WLFVWKgZenKLEV&#=AZuN3MG>krB4 zmOjn!#?4am&7}ozH!}ga&?sp__Wsj<=yYt76-Z&?!^|_`_&P4TvE{Za8RoRxxEZ+9 z=4k#p+5_|ZUHM^-tBcxwlF)F?Yki=smF9xV_~|_duU1_Un#HOL2?yne(Y>9aT=(dz zo&KCz6wPD4_QPpF91o8H!h%SSzkUM!2MJCB?Zxn`Qy|loYvr2t618hN5ZGB5 z#rHn&Tk;FO901`ox{wbwq#x9b4sW?3@wMg&S8j~kV1gGzkfx=mke3IEa_v_D5Vg|8 z3i6*kDql~(F=yW4u8~rM15v@zqckWW7==(0Ewt_Zfwo%^a?EBk`ye{F3WSCK{^EY} zi>N2b@IGj!aE8=#x}SMdmV+>h{mc?1ptE!- zW=?-vX`^O>5#&U9ruujR>-3n1`lLyj3{d+t;30k*%f|7gDxuWCKRCpn_sbLJ9d757ioBLy zI^wf87S6ABN=sh~E7Gf!YH4`|m&5VKPRFqoYe=-(mN)(-7h-()9{FKuc^R}X zRWlWBX_T(k28@aFx;jGhv8isVgHaK`VetGg@)lW30wMzfaP=|M52UVrh-PV$&mzDg z@FZvPS1|+at^(V#(0K|dpIh23BE(|27C9u_5J&kCPPTH*sy+4u;@lw`rz34s;J-+I z4(=It-jM*24nMsWF)d${^$Ok;Ucz|79xjpv5>6gk1ssJV+C@u$lpZ(T1;J9KGac>DiRd`A z!+sLH6}ydFs(7s4^o$GQH&P5pKQNYiG@*UZ3lXL`(ywUR^O%55K_0=lq55_DN^7~Y z68+BFRoK;?0TJg1;Y}xLaV|*k@=Ca$b?_1=9KqJ(?g_#<4M2{bG;}|QTWw@wE*=eF&cG4nix7=tUg-T@p@h%* zwouR5nNgtdoQl(e@Z8?wV<Xive ze^H|vnO+uj1HjXES4@Aw`DpF~a%%K$`M~CNF;7}BRqPAUr6|nz@Gw`v_e?w6S$mI2 zFUlgx!~pUqHGs6zjl_i)sIUqOjF_=Ii4X$QRxs;X%Rf zHNNBfj_kky0TCNCKP%_O?0yxrU9uaPlVXn&dti@TEN8GiDNj?8s-F~ZzTqxXQYT@`RiOSF$plMEq)Qud;ju5Tx{KR~t;fY&eT=)fcnk0%F zexh|FzA)eryQ@2b%Lc#3wu7Y()g}RORuL2aq0%HFaxIBT%SW7xm<09Vy z^Su3%0)qLxAM<=_LmYpgsE|3>_zROrHFr&QC$0UxjNzy9HzA8@KHwm(Y7$!W-Qf`p z+Fq~R>C-84BLaKq_8wmZqLH6^o7E zb~IhHj{I>rbF+_2a68Wl&7Rapyb=_Rh?E4?7Bt3lK0HH~_2t!$WM<;fHYlp%GJ4Nn z7@A^@a`F#jBg~LyI~T~#l}T0;K|253=S?M|EqdfN?XH_Mc{6zmf{YdC#pXK4c9aWyATP*CDA9DE)K zUdUGal!wAl&yqg#sahCKs}Pk;OTK3wd@ifJx}~(r(ckm&U_>+`WQ(RipUrFw z=5kl*AjM|r`;9Ris%W6JM2>GrYY%W%5Me|Av9$FGh>s-&06)iCpCSjFT|?BWPV26; z@k=Zu*<$<<64ZK`#AXwjq2Uk&y;=}k$nCyHo)%k$jfbe%M~rXpYTmcu5F+=Is1`Rb z^T;@ov?}>r;iYCOe&=cocVM?pQ}R(Lv7aQrNV%T?PYgg5TzXo_VZk@^r%!4#_zJN? ze$N|EX;?F&LLK2M{hSi_q!Li6fuV zT?`WeE|RZ6__(7#YyO|l;{eU_ZEe5}3j(ji;YDBql(vklYV`5Ug7A9eliOrV9$Vj`WdFuuw8F`{y4sZC= zGQF8%`OX6gOFAt(Pz*k9#z#j{R)AS#2=s(qLRIX3i!aM@4T_DmcFC*u@~=Ve3|)3q zcHJ$slsV&g$;$c{313vW{yRPcuhl-(jKn6RYGO~>JMDS;6d2L2OJXG3{w^%dA zDDD`HQXC#K^~f9*J31nYQ?a;QL;?j=f+=QEKxjqazyXeLtY2Ao^s3aFpiC!-63L_t z4lCNCiVZw@`1@4zP+1%fS1^l$A;i*tugWp0aq*3wRFd^XAaqZPCH*aQ=e}9xP;y^B zOy0%-Pum?AhF^4|da{Vbwo{X;Htqst(3=;N4U=aA$N`1#jIE4X5I7Ckk9#`*#;}5| zyW_wZ1Qs4n6`d<Q3X(>Ac3YR@e}@NK>!J(A_y&d8D5jT3#eeh(w19#5@+SloqbiQCOLv zKXXXJ=sj?F#Defl+hS=#n3+JP3roL_gcD~T-;x~Em^%#TvtnD5t#=oj*=yC7g^$4q zHw%usw)yS%gbHpT!EU@sSoVWMd^rCV*An(EnVsozVpmO@O!ioI{E$KX5mY|KnX~l7 ztp}ER7bO{_&H`CaWmjZ-i6Y%XS1=?D1;X=F3nEk~0IH|RgEF2iH2lf(EV55@i>S!5 ze*{!ubSNQ3l4T`ea}3iY(by z?=o=}t@O|)BZ2_8I}*SDXB$d|Bvo8-83;3$eYwKGo(864PIKC|K;AegkF6+>^_U?K zLdvKB)`YEf4=x|Lo*u&>ugDg+5oByr?b4_VC|w%E+-?AEY!0n}9>?w4QiV1P|H@O> zYaZ|5CMmm6?1nKg$4ztyzcpM7L=`onE=5CVG-AMA%9pgLWk#>YA0kzy6p+FhcFRs^ zbPea{?6-(kLLBOKnN8Ce8ILD*Fb2M^kqyVXS&BRLpJrF+QB`jeDZ@~(VhjzyhI>!gClf^dbp>-jxV_ajDBL)AAyK|UVstae>45&pTys6;dL9Pt&XzV^wXK6W=q^2z0luheG)^1 z1a!@)6)y-v7GQH*{n-Vl8Jt!|zH-zMdWhA3?$vmPIt}M^E<%r1kDY$(fK>11H_tP> z-?r3{(2f<@@2`q^uEPkn%s-w27}?oG}~UpS6({Um(5R_?kM;ZATU@YIb>4$ z-0k3s_zxaT^3wT-IvRD-VRCp9{FE9Q->ycnNlf$j`XYsK7sZ?@RaG5M#u7qZ{Rb0q z$by~(ZhHb2qMe|YE>SI@x#Z_%L^!2X#lQ#T%aLe*{ z9mJRmUz9NmHzuL7n;md)qpQ9MdQU)JsPg9RnZ%8%x3&;(JA`sZgSOzVfRgsu39yns z!NNuSTcF*yEE|P!w#Gb3@fJjY?f?LWAn9V4<`74^QPP}V;P!knnxW~3^v5jdl=$B| zb>Q$;vHFrO1xqR&=BVUOgCX?HTSU7kVZ;Bj+J}t@GSlgUH3+c2)6Uwt_(uVF90AWv zhH}P(xI_CMn$@GVumF5>5V&ex-4jzhJAEe+q6be%FSIlTAopiB6ee-UfjJ(NP*Rk1 z>n3B&JF-J*r8gf+od%WK_}P_o*NhcAA~lpH>O|l=jSGy6Sw#PRN2>W|g1Q)&zO}Or zU*Qk05YW?O(O`3_VsRJew2f* zD~=5#o6)ByTS;jJk9-2~pPfc_qXp@swcx=(aA21VH5%2Oq+d)W{V}_nP>ulgT zK0i$jC!%;RAuk*SR)Q=5?Y`aJ7HJM0I$nds9B^d6uj}lVIk8TBYB@(Uki)JkLPLqn zE?lkJS7EH|@zCZ%K5n@YJ^fKpB+M&a_*JXH^sC%_nlDNav`=m1I|Iltkfu2Ti3z~9 zMSG~&Qa#p8l0vV;L8Ra&(s1F0Gdmwo9RwB`w?#=;y~AEzu8V{}BTtydo4dde=L*gR zerDfX(hf1@ZQt~yc4QA+3~HVrRM;?m!43su;VQJaaj~5Pd{ku4s5D3fX^7wY9B9Q5ujZsLeW+gK`8EmZl-6^me z{p?Ku>z11xkWBm+Xhoc&1m|OfUC)33-h6MEp{lr+$qa^M%a#+3wO;Cy$*DXnldW(G$wA&6B}nRx{K@ z#N{t7#}sFC+aWjGVCL@?plzMV zfTx^M0J)Nch2}%P$pp3qG=M{iEFG&2=N37u2V;7+gStyW!2id|4hkf`Y$j&>tpC z1C*Y@0HBjc6Bolz|KP&Oz#q>8#@LbaCoa3_mqATCA8)`W5}GBzg~c7XZ!uCao~cX= zErRFVa_5E6M3xcH8Yw4q)>hY&?dTrz!&~wWU(~1eM^AsO2Jo$Jcd&q`bR-iY+_G zh&JhH28X$l7A*T~kXpHlPYpI5&-k(2mC=lGT>2X3h9L}h*UAfh(j2d2%aSyeXQz2Q z&TIwD9^F#cbNjeb$plLo>MeJH+iBB1XsvI;U1C!U;!okm_EfgfBMc0uHub=V1uAQPGZ7xxl(QT*SXm|8eE ze!}t_fsoA`Ddlsd6++n%MhB_BktWcWaYAma!p&Pdu`7)vb%PvX-ioQ40nM}A5y_vJ zA@meS*6j^Zv0EgQ!|WOCm_uLVHwe?UaBQCi;*{$->NHL>ZaOHPBNu+-pV(5HblBu0E!Uo+1iP`63MqII+kZ{^k;KnM$Y~(Kq4LCPfWtd z#65g`pV-vGG&gN#A)z(#$i5qqCs`|Zc}$|_Ebn)&~GdS@cM}59 zj(*_XSGNoIN<`RH^i1*hq_-V6Wq;nF;zrBRxDD@UadK zww2~VgAW&hy)nFOs(IU=Qk|~(5pT?C%M_0TF&&8@L5RWm`y+aI0l|~8l`yM@Wqv;nqI zR$?DE`eU>3wOt^;43VSm^gP>@XNyWbI{uM^8kG){WO(6-Rvebr+saZ0E|-U%H`h- zc6Xy;1*QR3)R-nQMH%?Bf&10^ga)M+fMe?SP8w}NKi0Gw>Ut*NH)~c9fk}q>kVLc+ z+I+I(IOYMJklpRmecQXU#e?glHDxZUbr!pD>Pi_VGi;Bk#__IMXKvWOGlS5pk+eru z#s})SHwf$2G3vKy%9ZG~c|kvsIA&<>YnGM01+-F+lWWh+`utEUMk;T4$yCra-BM_k zFsY^@|6XB!;fy>h%h3+5SH6zI*j|Nxd3ahSbjk(aQ2C+%q<>jVy*_sgFV90%>hd9% zz%9dQZ^>PWj@z|QLp@^||0$M^DFK``Psa>8Br6d@vc|<2=D}*F(c_>TI?Nb71WFB) zuW#q`FBW9gHe!jBk{Gr#(&X<8+Rf}am6=R7PAA3;;FOv%NDh#KqMPHB9X1I{p$ z01&=n&}m%?cvvcbOmExeDmDvVM0DCI8p*P-@RQIho0HXo2o0InzeK>Q*B_BN>s;_q z{R!&cmbcB~D|}^wv-0&9|O93crVn4!*y z((QQ)tTRm3v@QW%i~i0Bpz0YrY8q)%5LY;}-YZ5h6RfJ%9{%`E-P9>KmpI@S-hGYF znMP7#kgz@F!H26zR^6nHe*KP!W7hN$HfI&{%h_{pJwF~R6E{A3hxhbqu}rOeoYDZN zN&WOoM@$~`wkLdlW)0?AHq;kpw-qTT(7GNmIw6?jmcLeMcVIo!jTKaUp-Z-iW2bcS zx|gU_rX|Ok3cwCXUQlZ>ARA)@Li@ae*sA*$C3UXh6W{rwcRH{g(7+h+A7s)-%TcF> zlN_uT@Y~QJ>Ir}BGjoabdVF^5Y0sqVJBe%TVh@jM|2N3q1wLUao?C%dQoc&gAe}er z73TaVW5<%{0|6a!55pe5X#kKI@aO}c_zS;R0`X@(y6Veu>=>1cN;zt+{l#M%AQG&r znbA7P;_sTBQkM7b9y?TStNpF{rKeL7vV+&6f|u--MRh%-7h|qL|1n+=3^l)7fAhCD zO(P~x_IH>M`)hShYP5|1h}guf$M%woHQR@#Q`zJs2RU&un4at4`{p<!)s05$Y?aBGo3Y9c{QCgpWBe zXIyty=A#;_dY+#>WrE3o6ku6*Juap)YRn@8FV-~P?T#3_8d`(Drp41QaLPjmNoEc%d7 z8w`)}DFS1Hip96zz9>cb3ru&~rqZOL-LSDJfeo|R6rAE%5kZH(8?%NKTt-|>edF4vv{9^;bp;SP9OZwD zj``~kdCe$Ohu!|;PRKYPs=AzLQYT@I@U=I+8+;_8Ewen!6NAcYE0UQ7GDxV5^%+T4Hidej%bzOe}F^@I4ej;f3 zL7&q9JR?7ri-N5=_czhtD{$pHja7Zi*U6v@6ti zt^1`(_XsshON8?ks8)Q1xVIs9-(BC(JI~#Y2l=56=k{4`^P=^HeY+cHs*;VoM=_DIP=>KOZLX!#rmvS&w>ZLJ}<3AH!nITw-qMM0OHb;JkM7Ft_%;?X`^Py zG>Om4am-*jEV=>?@6MC2k0X<3*oFc5`g#s)_Q~2|_~iVn`C|jm(r0NI-vL0=Uc1sC zP2CVdk~2E$eN5)I!9$o2&}K>v>YjI(fwJA%&Q7&Z53^tCr z@h65^;X70&?=xJrhac|GM(bVMgSDqbWi3TbK1JPh=w?ay$X1|-+q0|x?HLh zui^fzTx?a=HT)>NQ`|a8e)q|kLG&H}4NTm>D9ap7cz#B|C(~pf_Uc>!eP1Lv@t<4D zmvSn8Ti>_G!F|%DE#&`v8-n7C{f$kDz+z>SHg9mLiwyhAxzN~8UEt)HYO44ieUB@~ z7RTm^=cY|F=^#`=UlC9hNrDTbyMI)QKEHDl1nmGFBA3;ZBlQP5N%mxKPK7U|Ca-{m zcB|WS=5HKJgnfc)qMJ3*f)g=+D-+*VWfP7xh479Ym|pg5@4^O*W{6RmHf&2#8H8BU zSVNHI(+lTT0I!C}%Ww5~-jHGgv^LCBBlTJ^^2{qNkvYphy+Nm-5b&6`vrv#?`~42u zY~ea0tjdA&Vh)X%#rxX^Ynp{!Cm?RJL0oX`KRvAz^DvUxw$(giy4t_Q?;wDLav~Qg z$aU!=_Hz`tOQF>hPJWmv{J5wK(?o-e+(c#A7 zO&29WY0?D{{WfQ+3hD@`I^L`DzxK(*3S4L zHd3cv1w8RsY|A5%l$3CY7oX3tSoPYgs7evn8pxR1Vt`YNvoO1lJf4HPGQ}&vNbGNAJDeL zn{=tMkIcx%&?)jDBR1+x+Z7?v85?SQsu@6%#?WRNrVAHgsNq@deDj*7wR_36_L*t4 zq%58Yw)N3K(qw&m<<{iMLj-0oUQtO`KDk7Kxurnm;$@V`s0ej^)k>p5(PegmCC@`I zS|kMU24r2)w4_GWWJmQ>Scis7%_TYla*?K)B4b4e8i_`x(Hnd24C#cg)T}1y6w|QF zvf!VU(#}@rOs_lWq?oIe^g)BeiQ<{f`+BQR=Z!z}D0XWu(2g)5_^Js!l~iLqOfUJ?5kPqFZ6joH7&pOmSmiyaKbe{E9P3BbyBwzL>7<4b)n{# zoQ6oaJ?qSak=caI?eqK3uF+R4;(O+-&uVCGp1E-e8p2bRc>3eT9d@sOB3x!{O-YHc zMzT!Ur*qn4Tg&^RPGgwF5c*P7-%woQ%+TYclRoKQl&TAU?4Krj0uCG_CesWwlzJ0R zMA|o$wcYn|EuNii?L=m+N0;b7vQA!q;eR8WgaWo3k} zQ~4HVIpH*kuS_#UqnnD=mUK{wrJ@bO0xY6TRK(C#zq05Q^VUsO(FDmV@24f<@#|79 z84-`-_7b#6W7G{=Z0eYik1T+0s;iP)TO9ivcYDEeqG~6VpoCv_H1*G}0VQ{=Qg8KA zoo_?rbFS%Z8afT-UKG7A6>{Xp&VtW(u6aq~quouv*Q^K}%3g}WPD{vJgkzZ%#%PhJ z{*d_0*4C*aIgO?3W^?}d8zpnH*~=`E?T^)UhWrdx6$DT2KvTkuB1T8wNIpAp+wI&b z_dllEX#YCmrLQ0r6Sn$#6zSg_nnTZ?X5#)Wdl$PEDl~UMg__-?E%UX_92zLnkUeNlrs7-tJS z7`P)(@{n^hqo|iAvHu=(guN)eqz#z#m!e!CWCU$JxQ4!sr3FmA6# zo=|yP)Xi_}KNwf=X?~rXXj?bx8mCu6tpSc2xiNUc$Hih}ljCwll}&>|AC@ec&V0Tz#>vokyV|N z3`cZ@a{LBzK|?ku=GjaUd85eDcFf}>9ETV9#N5Uas6;p!(WjzV{CqKUW+1q=HObC| zctaoVX;Gg=UUUOQf2m|EiLvw!;C)9bn2k6`rukU?rS|aA6%RI3w6IdU5Az|{ecO@V z7yM@28SoWW>>{u3f`)pHu*yX8T2nN{6wZw2VJ97#=2oI<843&VrmOwShsL z$9FNe4A?dnPm+HZW$LcQ+=cBGd(wQm9naOvJW+6d%Owi+H z%YW=DB%m=OE2N=p+xDm&+39C2;zMiaWQF~6QJ^Izz~2Diyr6dq^&$%9T{Zqr$843C z5dXo42FEo#Gx1IKavF!&eQ=G3c305o08*alY~*P5F00BD^aj?oN`Ozh#O9wS248uz z;rKVc=KkQ5yqY~TQRl2bDbF?A{TDV814ve2)QA|)mq3F|tIqroU-*K@hwlI`3078e;xe0yyo-jXr8qd+8Qy())>mbJRj9n( zFSJC*#>AD2E`#lOD=})9e{PE6`mKjFqw+5aJ6BZ7OMLn|nF!B-{~}KkJJ1i5*Jm`5 zydl}HH7Y@m$&4B0Ku&h*OAoYOZYo}AHr!O7EBQp~7|7Q}x~h8i!Kb`g&F`vv8bVBE znGt{jiBQQZl)2iw3TyxCT9j~1O?J<8K+y$O5uF<(fx5R~HuE`8S zf+Vkn9G_}FtMsWYg7foM9kfm=g6s*Es|e2-i$t0yx6kQJy?Lw6L84u|E8#AW(ADg`O>Xnrs^(l{zO8@ z!hE3rDwqO_A?Em0pCd7xQHE3SDtR`2y`kxH{jt=-RQ3!ja`etV3NMbCtdaE0F8j>1 zG`gz0Ei#5oZt9q5*gV#D-~fF&ihVPj%(0EspphnN3RF*j&~3c{@05(3+m}&F>A>(p zugDk|VbhqkFNcVn>_gPp{^L5sdScim$dH%{tgTtFy?d*GsR__fGTOviAYMq79V6Cw zZutIJGJ_5W-__o}K?aro^86J=Ql5O}#dH7?bA=RyjBh4s6nf25(Uni6TVLRMAXvsksJY2^k{wms%{g5Qo9TdK)HSSpK7ZWt=BcNRUZu_EnQ*?oVXAt$=B@4I zvk?6jyZ}q^$CX(vdkfgSqwD|G(Y~Lsa}H_MDz`AIojFR_h$U=M-<)rgS%cE1O!ms_ z1!HUc(^Yi54lE*dWE}Z%LmGJS0tC@CK3VS_*trhBb~VbW-vfj9-2HmOjh!L$h=#aq z7bOw>OZ*h9RM94jAySUQ?x2_ljrvJ1haPSlu;cOm{QxFCR`<@qm!-H{P_DAR zu{I}SIIlUYx=6Mm>P~w!xpJu9Vf(*}d7}e*pSDx$H~3i%qGYGppX6HBQbL$KH~&~R znNiU5VT2z@*mo`z!a}LcTI|vms}FHaNeGTL7Uz1sPV|3~7ov@wzgD+gvWOA}l{ZI) zD>(?6oKGaD$ZyZ0IrmBtVV%3vm3E*Fi<@{dKuhaaT40RXy#;UGLom_jr@wU1Q=o&s zFy5)r8&pIw>&rFPG%w0~PnrSq!dBm+To)vg;_PGAhj}|5&0*+C9~<5~TkV$>A}eJo zudwRtsHyeV{k+BMx-xlCX+Bh-Yq;tshPBFqtqyn<#foB}ik0^@E zy@=gcF(Xc{qoK_pBIDv}c0=*L^g=-Y8g4d4)|!hR7P<&e)2#pT?lTp~Uv6iiUc>|C zzW)Z|`h=ELLY4Ja4}C1Al1w9mKY$`U>1zJ+cp8Nafw`1a#HQSBgQtJ!Bi& z16_S6cgLv}@C>kfOV!b$`(@I#zb!tWo6I5KQ}1=d7&d&c`^&zM=tyFcfF5)y6_I@W z(VFwJ0~A*V&;q)kvmObXsWa_xY|`4TqE}}nM##-LQ|PNV~CZ~1$%mu zM{tby<4%($XE1E6`(t$Wu@?>Zx0O)EP3OciS1S6_ZuO?fks+vkh%A=l2v##!@2j)3 z;c{au_$g0x9-_q+O{M-@DYg)WgeCg_RCb698BCZdohoiD7)@=$Ts3< z&c-@rP5(P-nqvWsy?>RZ_K6rLitHq;8T1D$0Bf|JCzx0|XcI8?Noh-w4g?yhx4-no z285)izb8-318+I91)ZisoQ2f+X~7$?c|sK^BX3}h+qhsvgOxGzy_s`SWpx>6?&E_Z zq^5z0{PbK5Ul}JUaphH{2YvgiDlDN9&>6D$k=mKr_B%4M=(+MCpPr}HDS`1;un6MR z$fB98;A1Q>0i3@~NM!SWxe4(te1}N}zI)3t(A8YK;59$JEhZ+06sVE4m>`=A|I>n1 zfPpRnl#kA6nq$b9;Y4qkRxF@c4rdd$YF8B23_+2kUys04cuhCd(I#pT8_SY}M6wyq zw#NL>^_+wm-kH97BIY6wVLrUDu=@fH(lU=po0UFyGteixtRFwL8L!qIu2>Ni`Pt^| z`gDzz_Q^Vamzm;G(<~p-uyN_(dECTbvOT8Vj#|ysFRwLRQ;2fnazSWxd6Q`Q?e~?ty$x2^L88QA z82CDNFqYc_19cwa}6l`Dr zZ{+7zz-C0(-#~0UJ%|qY!@o}O1QN_MMGH4n{=4Bu1&gzFrK50;)^gVU(+6eaSHXmv zK|Yk#Fr#lpIzQGON{WDRDy={LrB7RRWEPLn%E3COkDt(kfh14QraX{MzKNYZG6AeF zj8G7eHmB$x$a(KrZ=I)PSnX%CA{d)g9FEpGmO9?u=NqDTGD*dGvxj43iL$v$i6Aa+{Dk3|y^A|t#3@M;dkhnWKi*!{L~ zH+Kw#p=wc2cUG&gL#8@_DIAopIF@*$+XH zLANBg_%gHA{3}WvXKTK9dN~9Jx(Uk^)}ib1ZJzY2%@BcwUZl=S-=IpxOi?NK!L=zU zf1h5Qnx5q_jUd@|KMhA% z;+M60O}M?c-vvpo#Rn-3HuvW!qp4at>iH=!Ftb?B)>s_S9iuNt)1+U)Kkvy z#HtTzpU{NL!-q3&cp$rEjwe7TuhjN?%^+t>&4EG>^to@T#t|aB5E@bG*mJ%8%M=@g zCgg=~gi#BcNP;(NoLVzBxkDEseS;$IqbCoZ&DczZf{pmy%NYcR))ZctKS*fAqM)~q zddx;1T^Me|jaNmLj6OLKeCw76DKA%40&HShgBRDRt#O(Hk3fP+cy$b$AQ&jkVYI68r*eQR_N}6fP%R}PXRk{p= zRzme3!;53E_KqU7UYF31Q~REU zd_}o&f%1MTX5h9D-Ql~MITRY%skhPlkmD|_>hf{iMID?Vjzz`WFGM?gRo zx$H=(~|B;?pY(;@;8 zRjHq85hgh<8IGCfWh(a;7M-eh>C^x`8t-j`w`XPUxH~=bJ)7!{Nan{OY(VA_CFJ?F z8@M5tiNu97+tV3|uvKbX%&HuL#@=AZtImlXlnK{#-M;}!j|kgw+=6|Zz06p#$)RPL z5(y?Jee*j6d1n$oxPCV6@|^|HNUHQgEQ%&&^KxcA6<9dL)z?IEM!S$mk5-m7F;2)?N#p85b0Q;gJnUse>~1VQB+mxTBD~LWb-eDU6WSpRu;e<|y{v$~Q@@E8$RdEsew>4M+%c~_?$RKa^M!Q>OaVF!1`cho-%hcF z!qIKV((9Na% z$TPI51j>aC-m@(*3Zm7?-s0#^XliWoEp*^lC^nkAbc~OTp%S;j-eooO5(250*GUP9 zycdAy>sSmxSL?;RkQT5sP{gu%ymIU=sLs0YPeAW%NE1y*O>Ml9uE{z|blnMDO0))c z`Ng#I3Q6hBPIL$Y0=aTFkA6wwM>;-11FcC_fPs3|7iZf-zhzNuTr6g-shj9l<8%XQ z`}}rP*g*e(4`1foH?kMWCh$?Ts14$ixO=}|YV?oa*;#BXk`QD-O#rtYpATb@j!+VZ z=wEo>&CaLc{j~!VPPiCtYtm3dx2kJxx85XvweBWi>(z8P7q|16*oHWpyub^e9Hcf2 zWN2tS4(xwlBf)r{YP+LQJ?SpNJb?dWw0teYz?(h|{+FQekl-;oH`BK@#1=BJi)1F- z$ZdUsNncI}uH6$NViMIp5a2{a>Zpv&eV6)0pqwitGL4m@+zp)H-iG{BIJf_oxIxCJ zgMIknEojN;uw&p=ZP(`?jgT>uN_3v#Q8&$M`oBpz|CK*CXTF>Q-ru7FM2epAxCc_I z#M|`bk8pfIHX}FaHDvZ7pspD(u`v#&E?lQRGNw8^oSOkKg~e9au~nw_h$^f{2!uSG zX)0e~%HodT`!V@_h|Ff~H+F!&-A6uf5k`$~?g&Ewp2o~G0B?9X-Jj(aLLWKD?-|nV zOxuXB@6Fy1G0y|eFG_8_pzo~SSL;it*LvDG>nD9t9e~D=fP%Abs@}RM9tiHoJtveU zkmeKL%3diYM*LY$-R^0){65cO%YqJVb~^OIXGHoPevQ!%WlGalS+rMmQ5a2J8wU0} z`5C+oNBu4cL31kd>&kGkai5FFQq+LROD{{^BQzN<7=PCkYG)5Com9>)mBO30vsM1u z<|GV27sy{FW!U4>+|0U+Dm+EfNHP}NxSfgu4OMRrT|-%@&NKCG`iH z>QrVe;ub#VqLiAeLtnyBqQW}`t27uMYgpF~0kFb&>*?H7X|$X^lNI?9*D*#wSKzI; znk#eyi9pwuZ8-EWdIB3$Kn~CP-~Np;{oFWYHeSHJlJ%9 zu6?I`EL(hL%EywVCeIua8z3g2L{*Ff&pGBo0vjEvvwr7T3&}s3%sdm}7k^BzQtERB z%)maG7>_CiM$l8qQaCZh1qKRQ$a{H6R$P@ z3T!4ddr=OKjq$K(RYpYmWVHj|?_y0}ILy4(%R)b?1&3v$uGOOaKcrq3T(jxhd^3~r zwWZV$nz9qK2aqK@51O^>$LL&EhbKN0qhn1KFh9MykXl1M5{u;rvAj1wXjq$XBoo~~ z3#rSYhPL5_N!bu!JkQ#Y`!UUN%XSiZBe8VfN2n}L7}K_HhPH7kQRkZvq!(0GL)63g zU;>Msrd^a~L=x2?Y7}s90?g)ok*By)G=(~7 z%g9WJpd1F~<~ z;97Y%!!xuswa5$Use1qMQyNjkmRox;<67d(p&9s@=d9u zQyi({&&)Rz!|iBXbV-}kZxz6lPH z;(M}OJZTRu2x_IO%aqM3>Z+Z$k-t$VRTqV)6+^6MWsFOpqJr-ZwB^?TV{hNd$|YVp`B zIkg-L0x^?&jR$j-Ct~s1rbYpn4DKS&}cjody%H^uKirTxdMiYn&EsYo?KV3 zr0z9zICVWna_*idUcllR-!titOk&<+fJt~>+T$|yytwlvcGF3Xk4<-w~;8kS? z;G9zl^0kyzmYx@yBi9K!i05#-5Yse`C@#Z5CV;$id@=dF%o*?2=>391e!&`Fv$wu^ zulsNKf44WBy@8%miq0+?a4yHAz)dcdi>!*1RH%u^BG7Ru9e*fC(#&ef=Dz&~Na%IA zBrXfYukPK{v8cF}q@rKE*C+;&hz>JK6OVjBtQJ>i0Evkb*>Hz{OJYJyQ9}QadWwOz zhR%OVxQ1z>SIX_Sd^yAj!TLph!xS!f`AcE&RO=S~VbS9HPZ7lRAxOAhof$9bgRAh` zF%D-Z2dn>DY~Lv)e5`I#hn0}-;eP?i(Wi0}WijDUB?K{7M`BsW-7%bcD%c0GlRBnw z%TWvV%M;(U$t{q2DpqO2V>o=vaA0hn1E{UNUkq_70b&qvc&Z{{&9gRucU?~py?nc< zf2~9dM^+( zbfSX%J2528~}A1)29nQFw8v3pkaQsB$2n)&c!prDd6G(XE(@)ivy z>D&x@$umUB5ZaJ7%kPXpBNuL)08n)%CLyeQQP!-mtY}lA3l7E!I6Gqi>moNY70rs0 zr5J0|ibxuB?ZykhMD@flCR$WLIed+7hOd^C&Hl4~04HWN$eSq2bDKqt5d|~fMENxU zd$UqwYA65S;sabePEuTqoL80aJ^P&4Y~57#*LYOy}V~cyl|F~4p_Iky4sfrWmXrUO6ybN#%Q}=tM zoZ4x1nCGw(xs%vKBV5zCBj|J)X>rHJiI_&S_=S;$eTqsWn+7kJ@xMdE@*Y;o#Obg9o7t4|yGqk5aOV!p%Fpl#*v z*hH72Loa<2BPT*0j!vcFp-c0$qc!R>mV(CvU3fa=Y}E(5>2BAh?e(@s%F`y6pKm0j zDuL->)ZNaQBwX!YUnLB0cE zDb*X>DHE*cY%(HmZhfsCOT58P;!fB7U(bdzWKy`Cb?{4*S+I9vLLsOZ? zb;9t$)4aGQPsYCjw-#O517kg7`hH#u+aqR#gIZ_Op}R9n**M^CIw{vRq-`?IR*;3g zgTbc0qe-ai%}2jotrAjR$pZm&X+pxIIW0yy75&o1P(VF}>)+Yh=w4VsorD>^g18BL z%Ya|{;U_S%g}m9sndKKYNR-fN0PFd36&*w#Qiz0I^?hR=jyFj;Rpmzj zxny(nfj9ts|Lx>-PXU5F+@wLnErawPNm!w8tC(37amasz(WTXw00w)oiNBYb&vyj= zLUhzB-4ftu02&6MLOPwoV^bcPu2bES**-DOT_e^mr8pH-;T9rwn~Pc0jE@XC?!|v^ zoqME?90yyJv$UjlxSiy#^j;wpMIU2Jq02M1N24I%&V@Iv$r32IygI}Fx$|Rc%@#OH zz=%}YUZS~dYsl2#71Wbo1I7pQ0bCy`%NFJ6y`qIf<#;&K1kl4q4QvG`+AHE zUAzU2(r)Y2%Sd%XC1r_G$J*Ou*trfD^5R(68i#&nM&vsl?jY1>Sw8iUb7Lq$iHZJ& zdv84i3ZuX|)nfv^jC(VWDYY`xQK!8guPRWr3k>D-;cdbx3WeacbTl(Qsiet~a&pGz zk)pO@8;{aP<*JW*Qx(c&W!oVRXLgdrEfHs=iqB`k$_v*E8RX-myr2Xpu21nq9h^js zx$Hoj;pDY@FQ6|(x>}+xAGkW7CZ6H-_+}YaWFn+muGRoa=B6_m1C%*5hZWxHU z`$|nCdU%p^Y(H@p*;x13_Y>HjxeBRMzW1ynMzFab3u7k&+zg-%{#oGz;3=KUEm<3H zzQio_KBu`CcC=`+@Xq6@ci0KeIXp^`EFtRHHyhy0_ID5FGY6z9|9*j$c!BX80w4pWjJ^Mbn01Vt< zic&$%$?0jgzDK$x70w!dv5a+!rOgXFml?@V!XBs{xW=a??k9ls!RbdaGe0=FL3!Tp z>elVc5Og^LWu3vsl)t+b&%yr7-(@_i&!;iQpdaku*6T{T#GEgjNn``TEs?;Ar1kYV zq1A1&=`-H&;nEvmy~H%S&bh%1>F-E-G^901Z|@7Zz^e}|vcB8^8o7~3r!eu==ZFF1 zK+ogt*du9?c`}Bl;l%3Qht_D-Ral@Wgvko3@Q?SUhp1MS_ur<^8Lc&Ld8-SYlf@94 zz5aKI)^+o6L%xgnNT#4*$B3mtfV>5aj4D;;7pvW+4_^xQj05FTf#Wg@wA=I5l=k&@ z&{q0}oN6FPLKj}ghT%3a`7Xq~_~Fw@$+fQoKOBC4iWr3pQQ~+AU~**1grTLtYlMRQ zZFMkS&Vsx446`|a8Tz*4KOaxmLGA$@w|_tx-)FJP;MgW+r{*e7B!F3bele%F$((Qb zwa?=$#dX<(ty-Kh4x;?vT=22$hxNLuiel?{>iXU3*En5dNCZb~(J%>NZZ#5xjJ|dt zylo?D*WbnS4a}Q~kJC=t}q))__ev+ZAmIo$*?Lls9={M$NSp+Kk zMqq`e^W``90+RZ18UOKF9HpSRrNlIOJe7#qR*67}%Ds-v|9+#fIzE>cg$bX`7>+pq z&%n4xd4RL8?w|DLjU;!1;Q2U=nRNyR?(l@iq;AlJ(lKk}z4X7KhLAmRXP$Q-y)V$k z@-0E_Wedn{KeHfYp7f#MGKANm?4KF>hTab)k)`#Fp&EOAlT5zap7^6v17mRS!b-QW z72wToJBqa|S#*CjvItsk{}Sz))1k3Uy;+DM$$VOJn-BMycRRt7s{s?9w&$fd78`NA z$d5usBY88zy)#0Q!0h?Mug}8*e-UmE&cm8MKrR(%TOGHEm0O$8egIRmZ`s+alFlPX zp?m5V{$6ww^{ z;hv(P>efs!4erIMntvdG8)67n657+wZoX;cvEG*&Ym9> zh*-)qT=m~lrd1zluG5~YjKSg&8WrITjOaq>xL(h)=C+i^FEu5Qi*G^dtc8s zjT6mZM9-p}GKB526G(B;(%uKl&>snTF^1WT5UL`_+Z;j3n_C!5jz8?eBS@cKcnHPG z#nN2qadG?dA+VqEP&Fz(dI6vj=TL;EMOB?os%t`{BVk;mL3%gru*<;_l0DXId|X| zV!Qe`50cAhE7kW;JKAPKHomik759;4l7;8AkyTHf^bNhR3%bf8VWRwvAE|jOP&_Lsxr`SxbM5% z4mxY8SF<)^_y5>SO8`GybPJCv>VGI)vzo~G= z#2Ii~Fx}GK`sm#Y9{(Va<_p#7uJ^kG7}+}|+;vG5?0**qH#qpH9avwb-REBg_`+MB zMSLQ1dmEbZQwRv%?TUY>QKde`^vUm#bkYk{@Tk@w+IxjxDoGsI1-!KFO>t8c8clLo zTfxB?&@c{1`f6G?Y=0)9CyX)9+>e3>%W%eoa@#H&g#(NhBGIontmMZD*!b>%D?E+;8!iGqk&9L86Ps2#oU@>h6dG^(Uz@hWEdoP zMK7wE$D-{?ksd_j2;^jw4R(6=klCg#NpfcZdF6b5CWS@Bvie~~{?%9qq|4SaZB1o%#=3%cUe4(uQl`lohR#piVGwJ22 zROYVY{~IWTLSWyPR2Lzb##dlBvDxo_+;e%_GQyDfPEcAAz#=HGsib$NAvNwbEVbYQ zv}cGiy$rFfGIqM@ak+hst>fU2c$!l=tk*E`dkFAfRvdCq}c_$~?BuCw{BTEbS9!Tcs?5rybQPdD+P38>aY z7yWO?tat@>1+6ulUi(tVG-LxPgc-TMV^<_}Qz@v&z&v;oYY!rDFg6!bYacdx#^;Rw z^DJ~`1~iLVvy&*oTi@^qDsq&DE#+7}JbQ-S)%$clA+2siZSAVZ)nayl3J|(7<9Fuc z#tDr|0H~oPBNvy;*ED0N@s8Sl;ox!lGSG}942=B|edM=Se%BngpF!N8Ps~zLo=hZ< zDOdDyd4(3)?WA7>z9F*#-~0aO=~=1sQH_b8XtRTjw^%Z4O}QI}CRgUbktH7q;W21M zDAy>qm$=m2!Q6(O3lHpy)nW?EmbTELzB$;1)d4~26kGcuI0zrlzTI~+lQV@|-0G(~ z?<|Wp23sO+p?ji2wkjVOd_7Z6YSwh>dChYJ^%QF6J}8kb^0}U?X3x_J%3BYg**XJD zqhg3|Q-sb>O*)=i-&&8@T4MYd;V3%Jo;w5zuE7d8mLt?LGZ~1$8iwHU3?Ss*tq)IlA`NZ-G1hvGtZ24X0*c1ft&YqtLt=Ow~+!7 zOPAKP;WrQfA9=*n7mXaFqW;P<7hkm#X!p>yPY_KRyw2-49G}>3i;7eyW2AN|U+AS<7O*<8f9zSDor_w>u8t9;3lw$*2mUV>Y9>cymyBAEl)D>7r- z%fHEJwxcA5=(Nd)DAl2xx5*Ur`3~~0unQ&yHE{k%z|TqSy)C)NR7K&F>UKMYa_jX; zxY>C4g+y(`;r&SE=UXyG%k|_9!CT;s5O`L_NV8}S+uN0*#;2yw`f#}@-92QL7QK#H zq7+aS$)!a1^e+^cbgyuAAo~xz%(TTuWiPqWTsbCiosB9sz?^@@TnQ`oaXzy!lRMp0 zZ7u(T{H&!N;6H0V^P6w4S~*yql*G}o&K%|Whl=IWY%ZdY4hZYtZy51V z`}ow_0l(NmIQrl}40Nh}${>YSa(NCB>E%18E^+|xiR=ohAV6u%$$D$EK}%nbe0ut( zTWJkd5H5QR-5S`lwthIMFu}_py?6~iwrIC5MS>%ex-pWJ?b|2W6JjQd#~-W zGGdHNzw+(%=1=7ku)ylorZg4fl{qva@Tn}t>283OVvZHkSRbI^RnS|fd$x7UOkiz* zqk*aRA@k4#a9>%|Yaz6MfB&`zxjFfnRUtBjk~N8o3otEB^8;`W?c34=?z^%VOAf}5 z>Kl5#9j9>lx%_EEGO%}sW8SP2n5$H%2w3d|Q37WX9UzNX7ctU`ebX7ok3aC#{IA3P zT*d7|Kl|$aN2P0xm0>u?+QV!g(2?>aAPg_d?WKv?ghM!inuI2}Rdhi}yPUf5CxgcCM*0pk8~p2sz&4$hh92I)o=Z3Eq8DyMHkMx+Wjf;Zs<7n;!W0duW+sHU9fXyhzd8z!5A_b#v)g{1|`T1IAjy?2B-sjcO0X zOi_E+>3Z4tJxv@>OKq*sEE=VHQ}^4meAvwWm`Lf&>V-Wh;9|4cLz14BexcO)EBpM- z3{7~MG&XwE(!LZDg`c(KcW6Gs3AsycHz#dHpaw8(?h-y7@tv}~31Q35HNfkQ^G|(( z9bOC|rxS&BU>pDeQQUSwDfqxrmS3?H)FNx&XF(YhIdCj*W7Gn;?uXDUNEfs znEXR3QydI?>!3k?C^#d$bMhzfyYV3?KP6Y;=rL*tR^IM&l_%}qi^rd0;{$0X?Ux{> z%>{%C{1TbpT;CLi&aj7SZqa2M zqLV${@GatJJY#L~;#ncZ&usvDA+xuZmNhfxw=I7%=ytKtA3BaZLqx)DBy^#ZjWA^2 z?b57{&s6^0Xe+U`1M=ijt#E5TMW9k`#rILf-X_0Ot+p>i2Wnw2RtGUEC>tQGGC zXxQ3@L(Mn|ejg0wYD>?Ngz?QSSlN?IiU{$W*aHHedFCJp&8qdq3Gz&;1wD0~yvy7_ zL8k4&kJi|}rPn~c4egKp|MU$HF}^d9jp5x>$0mvXT$uOCduoH@64Wv&dKS3UFs!uz zh8TwEedjuwf^s#d7oB%qp#dYlz8TE9PIQzImQrQZN`b?d_#S@a_|Z{4U71pXNNG*P=2?S`@dCM_@J7 z3v4ra(|TqY7a9?;^)*Zd83k)XgGNMSlptW4h?8i|DBkClxvQ^$49%#u@hXaKmg3Yu z9O}SbJbLE~cCKyEshEJGxs$S+FrE3c3h^UHtFL&T!v2Q@g-bDqe9mCgb#6egt0P$)ddgZci%Ok0@(5g-hb!7w)AZSR z{nX-Mp1~EKx6q;Tv;J!H2nVE*FdcZ}SOvwKayv+Y))p_i<@nzrnnm1m4h^2H`%QR0 zjS`LhEwYawOj9niF-nS<3`c*3J?8|v#{k=IW7}LLb5R59AMt?Z6C;Ve-LXuv9oc$1 z6-v&Et{)Yp?Abn!tnC8^h!X}Pj-VO+F%^VY5)a^lK(4Q+E?;F0AcOqx(59*n0cH!` ztVFIU0o}P*S^D~6j+ap!(Cte|bQqJ?PsbqmEI`6C<5f2Ya{>5;PMZ+wMD`S9lUNmY zf;MVuTQ>wnvV0liw42;?T_ZOYpkkjgd8lIS!17D@#mnAmuKwzZZgWLTMwFUk;8V4} zCRNnPby`>WifKOWjH1pHw$>ul^rD?QkCn1*#Ndr7EO)qIf2 z9(vA8XN~$0BTps>hEa0sY(~;TN)E;FMRt=W%K$M{roAbK{ zHwJv8<`5PkY@<>!YDkEfeAT(b-W>+jIVDsoE-Gdha}4d$p#?NuinOYOH@I{WCQJeID&sae3r!`B%?O?`j;SAoB^0~1*l22Fy0AZtapnCn>**@+9W1|#+KtHmWgxh#odE-lBpV+1`-{9w$_xUK^*fIiF-H*)hjL7iZ&ky zH%nYS6(mW{{@RkrNI!SZ1Vum!PLg<3^hJGqGOW&KQ$$0p(n|9Rf3($@`6I%Rcbkpa zWn5R{jjRV0`aRk&;z#nsTkbCq?}d1uPvk8ny%T&!u>PYMVMZ0v&WM87RW;>rY4CT( ziFq~%q*NYHk2Ct=?+5=5{9$D1^b({MJkUL#F@W(_Y-02TvZ*D^)mMf zFTh_Pe1IxoqCPJ-dpk{H_-4W|_n7Mn?FQJDOAVw@|J%LF%D16AK;I!n!^@N#8dDl= z6;|l9HKpsx3oB5Q#Fv#Xe$L~&q zbGRHriarzI`0u_2T?`tzJJu}S0ie@Rx;Z0AR#JZg;lH+RT6+F%)h?y{*$_>k7jQig zCD>-k8ThP@aSc~X|TsdP}4!xFxP5a$<`_+>?>rpuo71NGOq4V~rv=|;w+Q`OEeOkO)k z`EM?{kVL26-*-SgPVecP&aXkukQukPdvGbVL#H&M?nNF!>dNyX%9Q5zfzZp~5ElVD zb64s|-5z2)4>P-m6WTbX^U(i{0Noqp9B1qN%I?>S+4KRN zuBuP>oX7R>N%_Fh5~Ng<^z!&9t1Tqx&J`FEGLMRbGtXYL=r>?5%N2qLuM&R1?g!EV z$lUs!T=T-e(|S-5b3jnMs&pl{?(=vaPe5zbkOs`0{fW9we~APl)1fJ@*1z`YV2^U} zi-HNOyuqqYp(3W&j9NupSC($VJXe+@Vo8TOw9{j?#Q zMv_0G$h$R(=P?qEP^crJMYu$#%AObPA|%E!@}}xpt?&i@tRFQp-2!_I=ymHKt+9+%D9w!{T7LM_@!u-j%Qj8?%z>*?0Oc8vcx&OM-T}~r0Sy+20?E18*s~m z&=n3qaqc(O=ggU07E(i!d@)!7_7)6GlXpXAvoqRawcASMuP;});8CCVWy1Fdv$fN; zr;KK6xZKRY9oeKkfm0k*YKFo53A%lk<>q_Vsrpe9uk|^x0X6qX?a^istfr4*F{_3a zN-@kkRsn~lP67_bZ(<Z^Dr=<{Y}5tQ)CPzob7rp3ge~=c z4D;LnY#ZA0@%fO3$Vix}q|mm6xwiry{(Y_mBz>9rs(TQikS~t4S8x$_sMKC8Irm9F z+&dk^`S4Ckw7$w3zT>p7S?yCu>%h`y3L92D2oD`Qox_6q;^!bEWfR&=#RAQ<_**%i(4u9W9^q-drJ z9l#5;O!Jv?mWeQXf-(3D>{oXA%{AKewE2EH>91meli@IDUn<2U(}-s|ORwN`d47=A z_>Ul*SaYdn4>&raW=5!SFG2{8dNwqI$28PefSDMR3nz z302m_RsMDB96UUA@qEZdJX!7XDXN*P^V$lzZE&%XB@lT`sszob8e4RPiMqv=He=iL z(Z{;Fd7RtCTOOULY=v`Eh-CWLM-(LXYt8tPX)dR*;KQ%`O2h-P6V`oALG?E?qj^7# z@F6%raG#?d#p)g7*W*Wa@Ll-uOpp^`MwjGv>BF9rdFu)?!dg`ELil@-7Dy&aB}q{l zlv}MG`WUBCD~|SFK;paoxj~xV^L5+5HnV^ZirhdTh*wV;(m&(!NqrmA$% z>L)kmI^uY7$ApV^TWEg_ZGyq-^^^-OX(0BK9=q(r$cnC#o8R$)+gJ*){3uSic1bMRqL#@a`?h&AMf5sAXz#T_gXqkV*yDF* z@{p>V?=$yDe3wV^xw5uS?5Bz4Wn_KV!>KrXDgx}F?>KvVo$=}d}Fo6Wt-pF=C%zihV)0tDN`T|xLMTHSZ0|q-( zM3e4U2M$^M?Qd0J{aS3EqbrSeUdT1NcdEohX1ey1m6_Fk>Y2aRWSvA2foXURdNaP0 zldjV3OyHatc%Eg{TDGEx5j1%8-QycV_r#*v%?a8JR!^X!j$gc;N5aR%KNAg5(+-3T>H(|;$0m@kW(Te5OUIgR&R3c83Oms%hh z6}A2z75r8AqN#@5g`nh10K;W+AWr*!dH_8jbYsQQXD~|CaRZ^I5f{?a7;iujxp3TX zkW&3##$q?`1V@((-Xb2zcO#c%8zO;Sy!#4$r_A`hR$=4l1HLI5mBu35{T_Q>f|gMi zcjVrz3+8%e21aJ-Xr(U{6(@&8xbKaQ!eV}IM$*CKw-MW}%ULZ&{ns1(N*pWuy@N4j z1Ij#UC+)9${IWLC82-XON~6*)WE+8$ThOA)XhqPnpiV#Yv!S;WnU&>d{pNk!3zaJo zVzK(XQ_k{LDF$y*!<{_HsK7|#NHeF))~}R&(u_l_x->gWnAB({r~}$$#yrbMc;{p2 z_MxQ3goUxV)WJWD^xgP1C~YLT#Sjy5qks`(_7s27*HaJXAj@2E&BQgqnO$Cw!NVq zZ$NS2J~p~NlI+jvJFLbMD*I$RvdvPKzD&qh`#e2ckq3yZ9f}{^ zoJfCkz9)--bJ#1JBde}xI;#?%6A>g!gSHkd@k0W05@T_Q_GBw=&(lrS95ohqGqd3V zV_(L}5T(kJ&Zy@*;&iTflH@jzl9psl;<1oTgO(4no?3(bqpn<1A6uCcNdf(So=qLZ zz$^VkmAGoDf;m4ctUI?xpja8Q4}@Re?oHUwyd0}0dDa6=z|Pb6{k08;UD#Vuijc(W zbQWeG{nNJ%&w8L-Y6OwutYG+Bk=kaIBD_{};$Z&dU55%%>Dh(JL+^t$XM)s0m%DH!fJf_t#f z9>kGvr%d!Xt<*Jyy%HkdGiX25ehm5-kwq0?wF#FUZpm=od_>6zC?PLUZDGNviw(_G zx@AO^NeBVRL{hka@RABSALS0@H#-oVJ=~@uBt1+5fi@+D84PMvH_$Auh1WE1;t;!! zZjgqC>x9KoG+L^(`4B0<(u>4&}_>DvA;F8Ym~SMMf;f|OZrMyOYc1$?_tGkB2x|>4j}D&lad$l$0JspH87!P-Z?=bv`lAUP0cb%xbmsuhaVlP8p-$mgP+z`3m}t|M0o$@i%R_7F`bnoXe$D%ndDv&J{Nqrp463xA)V52>%E$7!xhBs7mTP^RTA5qhl6wY|oyDok8D6`;b1Sr0^sjlP9YP|d zEC^K!zk4>DX!By+yJ)a6nfVY^8?hOXg*xA2@#qr%9&YpsWb8~1Iksnq9Ql^^rSm$0 zjIf>MVNkLJ0;}Jez|;FAAXP_0^XiS358^b7btslG^QI&nu96HrgO)xHwG5sZ5%BR?cJ9i?u zMvPArs^!Yr*=iPx_W-`ANGhgea;GrsTc z$0x`wzfIV^P!>6m!n-EdZgxtxv3hMonQunDt$Uf<{}$Ex#&*hx)(2uTj@$IiVj7kV zt?FVTM7ShF-~>0G$?wV_uXmM(AsZkEEE1OZ;@?{71|ck65d_a)rfhj{mMd1z`;jl{ zm1J?U?y|r=>6Q;=!_J2tobJt=?2DhGh1%)UKXH>f#y?YI^srAa5C?xXfLSH$aG{z~LjS9Fh_HVFJjIZVDe$MZM~Y)!S1N8yao8VTxbt<7&$E^EJ9K zk_E-8F*rqRpmG-rE-};Zm9v&iO@H>&ik%vuz~?P{;+?n$f@G-f&IZx7B?oB$H;nr5AoMOIPdWiHwZuX7d%XQ!X&_$4@j(2@uL z3T;+ggvI;6{*o}ZUqdcK>SnZY!Pgd>cgXc%DM zaX2I2ysE4U?+oU^g24=Dnv6bse;=2(J3|51tuP*o1I~Xe_chtSfc5homMW?DCV>@v z_HGI>(aq_P+@z5$+BkJ4%Do0S7arZ|3YIz2U)l9>MVrc6V&yLaGzL#>UJ`twX=I1F zVhKhnbA$-hG^DQP3$@?*DAyc?TUva5d^eYTpHW{QG4G(}`Ts%AX?fp=3(V-HArV+)U)bmntUce0hAn50cqOUs z6eIgxb%;NH4DSX;&VID{LVgHK^Snp)MHe=0i^OamzfBHHWs)qlC;(Z3{HmdS(9JNC z;6lYR$yFcH?W%xBxf?y4LPTEtc$*}nTlwp3Aoc{DQ{kJEv5VW2?tUCRSJXuSV$xi> zC*S7rAJdIqGTEGs;U9HbCiOGgsP-vg)0M>EU0zhO+h0QI7cc|whjBvKS0X& zR6S_>3DpEysSo2{ji38y4Fe`zNaso}1fBYl-J9ktdD0A&eCPYo2ah&rg$Y5rXXzfW zabMOi%!oHM_a49s{xbRj(tn6|<7nYD{J2&p6D8H<_~9VW_{` zU8BA1;(h90c(gJ6srbcAdY#DwJt1>4Mwd8ce}?>wNjw)xXpgk@1()c!VH4eMa|LTB zme+*@4;e2gwrJe7G{uffsGK)!RmijhqSr*ParH7?=k3v~;_8;sI!w%x_igQixTAv} z5VHigJ-SUD@be(}IEOC` z4T-rX;u0Ywtz5ANOUpB=le!dn&;Li8=hg^K&x)l@O6=?8l8H9kn25D}RXiarJq(*H zjGFT*U9Z`^m3Pu!paJCe%_&8mvIwjX#^@XsC+F0lD$XU?gmFKUkGb<_4|gtWLY;9V z8%0@8!HcIz%aeZ*fIPh4Mkd>yIwcrYbZe*;YJJSX+frTQy;d6AX1A$S^zpZ{{U0FN zB&MWmZHW2yO+FfI7O&RFz?>|O=Qe>dlkvh_zhPK`c`G~WL#OaD`9t@ z&VE_qD?s;(3DE;>ROk(DQu)UFA;xE#!eFhqGo)aK+b*Q0rJ#Al@#N{zY~a{}MOMUx z<<4??X4=S1Gm0GHJatH79gn#@pEqKHZZOkQW)K<4n(7;IYhwLg{1lHuP9vlWHKrIC zOH`bqAq>KN{ZBNE{mHJAL^;IjG_TVpkaKSvkO3&?O{mB%^Y-V|FhbTP@M6Iti zrW`Q_&Is)f%+2jPKLCtpDuc|9x!^1VDCiH-d2}g<)=e8GB%`BS=$ym|0b86@b@RW| zIA&53YRmP*>>8l4BRm(BF!vM17hG3nfe)ZtHHi%58Ozp$-zYw+FX#=;t(*?scepRkFTjye6M@Lnqv+AWFRF zIyKrbbG#Q2E`&BQF$jbq{nyq25i9ql+e`;lO=V-bGE8Y_$`YHZL}(qVNG7`H*|Gy1h;IY`LR~wrGcTlF+$>j;B}P0b@(faD#WbQFW8%Z_k{MtHTx&4(&=`{OEOPi|86m7bth(=j=B zk?9g@Vra7RZ+1;ri^D8#9p5Z%aLJomf?Z=jGM16Dj+gHpUcKgEMBsJ+M{h7U4yw?I zLxO>Zre*3+ydB!2_qdJdlN0*C6rEcT!*eyj+DxVHZO_x!K9u%GhUHD6APr~C*-$o$ zeQ;or^8#xotiI-n;g*!+-LfC^>xos}yEC$2M=8(4(_yD@qtUW#AKu_vnsklEFSr*g z1_+KnhnA6IfeW$o-Mg(&0CHOBnh3YJ^@~003(q<&;{H%Q8`wxv51_wC{;}P$-Ebb9L$dcn1$x z4Z~3n{F;X$-4~xIkDaJ%@R|Eq7>ZdvsZ;hU?JWbi11nXQ!h+QXT@>mECkGC6Gw-MS z!BB9#7E-RM1NFMBww?uZjcnlvB)-B-ND+CEfy8ON+Keynx~Pg?6=eQ`ZDdz(Kj%5| zGd(ENe#rtS5P7HaGN4J98nyRBdmJ${_g*p*?(N0YIxw#zB;Hzj)9Xxh@p>X3_-dzB z_J|E&u;fhG3*9(Nsz!vGbpk?m?kaZ)CThRcP7Nn5+ZL(C^;M>_CjS#>)-?;@ts zA0%oSD91Yh#Fg+OB}O6?bg}7JhxN46diM~3)bCM>Iz4+g4^FWt9xxr3Sl}KW{yi8w z`0&DUwq_qi0A|`8=Tf_2)Rec$?q-$RFT@%g!k9hQA$79#^NNu|01l8rocWrQOw^xS zw_?y42t>c|x0>P$e4Wo8Mu;Dh6dJLtm3n%9LLT@;pU`S(&D**L2?oQQFhE}_ilz6& z0_x75YM90@JH(5$(SFFwg9PH~c$LHJbnuSOucHqDsUgnct)ub-nP$8sa&w3TT$GD= zTLKANdNG)k%125=O)y#K9{6hz4sgRC{{MHtqKsa45Hmg`fSh~wo#{X9Yq;e0_~p+p zD%@vO5aeu;q-pLjo;g1O7N3ksKkh3GO?d4WEZ`2xx>^7}RL(rXo&{<&8m!Zv^w&z) z;P5^WKBa%q=bk?ec;|n9#QksQV`bQbwPlz2R^P9Ak45+l9*|u$a}2NZaax=FpnU~J zlyha~B!Gk9oz_v_uxlT4u=yq2K!CnX+AY`vn3$R@PIB$3kQ_dlvdsu8dI zfAaHMc9Tcuw#Vt=Ryg`Buk-}-$aakkUmaY*HjnwYBW}0I&jY}QPXIxz@uAh#%B5&* zW-7fj)!VOf+sE2gc#(>LhFyJTyt&9sCkYfZ+TD)=Dkf)NG|XG1u6W$P!u-+d$8YqR zy@R}^u_znQ_S|v%<%ZA+iu!Wz`5G%EsUv?q89FVMFe5=jY8riJ=k;;bVv3xAoUGDv zKzIXSK=#|$EOB6E{qd(tR0=Jkrbp?i)H@_JLUwu`8>S=33JWHK-fdY*26B{nO|p`V zFZlA{lcHJ>d)56WU99&T8`eu4#?XlF#1zI3%NvPg-Lk9E``=^}J9`Q(5BnQ|ieN2I zK{h0T{=Bfy?jDy;Pa~cc6|4z*8$sj00cL_L$6Z<$#If&u`=jADMAAG5w5X0qxk!C3fo-6xI@C8gD z!Nys_n1!{Jwy!v{lPdbwUp#MYP#A}4i}?WI7^z8=sABmLg>R>NZ#0}1p(ego5uv@V zsd$m}+e83L6*mk4#UdDc*o*d`*WUvcManr!BFzz&pZvUMs$5ET5BZ?<67UuWD6Iew zy!PezUr8@THL^h&eA1u&NOKjK%#B{;J1$1Y z0~xY}t7dW`{SkmN%d(x7x#Vuohq3wDNrMmJKnDa&@C|p%W zD6}6#i;?WPFfgSsv@-VdzZ&3;~8U!v=rcIgQSL~iC zX9H_E30sIk6y`&S@4-VQiMPBH+0)y|GI@m%FVPk-jRmO z`ODm=xv!TCFtDe0-1Qeu5P};w08$HwDzen!dvag~GEzrN(myhYc?ouSl^s+US<}5F zP8)6Ns?I{DN}V%H(~rfNr~th8tq+%tdLz^>-fwN`Ig#mjtSt|ac>OLNg$Uz&7l za#)a9)NuU}8t_6q3B)5Lo)x91Qin*{Jrk@l_57jXNL1q}>Yw4LI`K{)gN(paPDRSJFMb6f%^L3LzQbPo-i+C!)Pg0vZ&N=ksRzh?Sq@Mm@&m-)x}N zrcFKT6R2e^`*w0in+IdwiG=LZLDNW89+d1>(myamZ*3nvm(07@tr(xfGcMfikyryy zHj1N2-UfR-rOWPsG^jUxNnAh^Ri{)6KQPK>YTCE``H82W1gdS=jaKl15}YWe;3v)= zJZ@Cgl1#4y7Dn@oCD5*~F5Eon3A*1Xm(MVnp6!=zyF%^1J&H^*#1IpvB=LL@n< zvg*e&%p(9?73}n@X@pB4(>E9xwJ)3gGRJa~FbmistKU6Fk#q6sVqrjZ?^j}KnJC}` zVm)P47`flLzi$?)YWG}kpa~p-(y#eDqoaPKNX~l+5fPFuD?wG@z1fhD1c+k1NYGF2 zQb%^=CXzedm7ww>AC=Ds8G{6BaDWXzp;4@HBpp}jCCv-@Y;|WvywQi5LE)osgE_l! zwaeGSBjMH}}ErF4CiJ9pP1A*=!Pu8Af1aYHl!susH(HN3ecIczw% zwcc_Aj^8@m)YoaGIp&qHF2Xbz(mOJCR{xrPiFC_

PC_uX=4t?85w5*C2%+5c7T@ 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 ^X~X-^KwgEl9x2B?am9ND4Lf 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�OhAfiVrxOIV+ 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 z -Date: Sun, 29 Nov 2015 14:44:22 +0200 -Subject: [PATCH] Revert "x86/mm/mtrr: Remove kernel internal MTRR interfaces: - unexport mtrr_add() and mtrr_del()" - -This reverts commit 2baa891e42d84159b693eadd44f6fe1486285bdc. - -It currently breaks nvidia304 driver. - -Signed-of-by: Thomas Backlund ---- - Documentation/x86/mtrr.txt | 20 ++++---------------- - arch/x86/kernel/cpu/mtrr/main.c | 2 ++ - 2 files changed, 6 insertions(+), 16 deletions(-) - -diff --git a/Documentation/x86/mtrr.txt b/Documentation/x86/mtrr.txt -index dc3e703..860bc3a 100644 ---- a/Documentation/x86/mtrr.txt -+++ b/Documentation/x86/mtrr.txt -@@ -6,22 +6,10 @@ Luis R. Rodriguez - April 9, 2015 - =============================================================================== - Phasing out MTRR use - --MTRR use is replaced on modern x86 hardware with PAT. Direct MTRR use by --drivers on Linux is now completely phased out, device drivers should use --arch_phys_wc_add() in combination with ioremap_wc() to make MTRR effective on --non-PAT systems while a no-op but equally effective on PAT enabled systems. -- --Even if Linux does not use MTRRs directly, some x86 platform firmware may still --set up MTRRs early before booting the OS. They do this as some platform --firmware may still have implemented access to MTRRs which would be controlled --and handled by the platform firmware directly. An example of platform use of --MTRRs is through the use of SMI handlers, one case could be for fan control, --the platform code would need uncachable access to some of its fan control --registers. Such platform access does not need any Operating System MTRR code in --place other than mtrr_type_lookup() to ensure any OS specific mapping requests --are aligned with platform MTRR setup. If MTRRs are only set up by the platform --firmware code though and the OS does not make any specific MTRR mapping --requests mtrr_type_lookup() should always return MTRR_TYPE_INVALID. -+MTRR use is replaced on modern x86 hardware with PAT. Over time the only type -+of effective MTRR that is expected to be supported will be for write-combining. -+As MTRR use is phased out device drivers should use arch_phys_wc_add() to make -+MTRR effective on non-PAT systems while a no-op on PAT enabled systems. - - For details refer to Documentation/x86/pat.txt. - -diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c -index f891b47..e7ed0d8 100644 ---- a/arch/x86/kernel/cpu/mtrr/main.c -+++ b/arch/x86/kernel/cpu/mtrr/main.c -@@ -448,6 +448,7 @@ int mtrr_add(unsigned long base, unsigned long size, unsigned int type, - return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, - increment); - } -+EXPORT_SYMBOL(mtrr_add); - - /** - * mtrr_del_page - delete a memory type region -@@ -536,6 +537,7 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) - return -EINVAL; - return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); - } -+EXPORT_SYMBOL(mtrr_del); - - /** - * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable --- -2.3.10 - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch b/kernel/tools/cpupowertools/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch new file mode 100644 index 00000000..939960bf --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch @@ -0,0 +1,192 @@ +From 760235cd6ca8ae0d7509055d75a0f1d8b3c60668 Mon Sep 17 00:00:00 2001 +From: Lv Zheng +Date: Wed, 30 Nov 2016 15:21:12 +0800 +Subject: [PATCH] ACPICA: Events: Fix acpi_ev_initialize_region() return value + +ACPICA commit 543342ab7a676f4eb0c9f100d349388a84dff0e8 + +This patch changes acpi_ev_initialize_region(), stop returning AE_NOT_EXIST +from it so that, not only in acpi_ds_load2_end_op(), but all places invoking +this function won't emit exceptions. The exception can be seen in +acpi_ds_initialize_objects() when certain table loading mode is chosen. + +This patch also removes useless acpi_ns_locked from acpi_ev_initialize_region() +as this function will always be invoked with interpreter lock held now, and +the lock granularity has been tuned to lock around _REG execution, thus it +is now handled by acpi_ex_exit_interpreter(). Lv Zheng. + +Link: https://github.com/acpica/acpica/commit/543342ab +Signed-off-by: Lv Zheng +Signed-off-by: Bob Moore +Signed-off-by: Rafael J. Wysocki +--- + drivers/acpi/acpica/acevents.h | 4 +-- + drivers/acpi/acpica/dsopcode.c | 2 +- + drivers/acpi/acpica/dswload2.c | 13 +--------- + drivers/acpi/acpica/evrgnini.c | 59 +++++++++++++++++------------------------- + 4 files changed, 27 insertions(+), 51 deletions(-) + +diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h +index 92fa47c..8a0049d 100644 +--- a/drivers/acpi/acpica/acevents.h ++++ b/drivers/acpi/acpica/acevents.h +@@ -243,9 +243,7 @@ acpi_ev_default_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +-acpi_status +-acpi_ev_initialize_region(union acpi_operand_object *region_obj, +- u8 acpi_ns_locked); ++acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj); + + /* + * evsci - SCI (System Control Interrupt) handling/dispatch +diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c +index 4cc9d98..77fd7c8 100644 +--- a/drivers/acpi/acpica/dsopcode.c ++++ b/drivers/acpi/acpica/dsopcode.c +@@ -84,7 +84,7 @@ acpi_status acpi_ds_initialize_region(acpi_handle obj_handle) + + /* Namespace is NOT locked */ + +- status = acpi_ev_initialize_region(obj_desc, FALSE); ++ status = acpi_ev_initialize_region(obj_desc); + return (status); + } + +diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c +index e362182..651f35a 100644 +--- a/drivers/acpi/acpica/dswload2.c ++++ b/drivers/acpi/acpica/dswload2.c +@@ -609,18 +609,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) + + status = + acpi_ev_initialize_region +- (acpi_ns_get_attached_object(node), FALSE); +- +- if (ACPI_FAILURE(status)) { +- /* +- * If AE_NOT_EXIST is returned, it is not fatal +- * because many regions get created before a handler +- * is installed for said region. +- */ +- if (AE_NOT_EXIST == status) { +- status = AE_OK; +- } +- } ++ (acpi_ns_get_attached_object(node)); + break; + + case AML_NAME_OP: +diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c +index 75ddd16..a909225 100644 +--- a/drivers/acpi/acpica/evrgnini.c ++++ b/drivers/acpi/acpica/evrgnini.c +@@ -479,7 +479,6 @@ acpi_ev_default_region_setup(acpi_handle handle, + * FUNCTION: acpi_ev_initialize_region + * + * PARAMETERS: region_obj - Region we are initializing +- * acpi_ns_locked - Is namespace locked? + * + * RETURN: Status + * +@@ -497,19 +496,28 @@ acpi_ev_default_region_setup(acpi_handle handle, + * MUTEX: Interpreter should be unlocked, because we may run the _REG + * method for this region. + * ++ * NOTE: Possible incompliance: ++ * There is a behavior conflict in automatic _REG execution: ++ * 1. When the interpreter is evaluating a method, we can only ++ * automatically run _REG for the following case: ++ * operation_region (OPR1, 0x80, 0x1000010, 0x4) ++ * 2. When the interpreter is loading a table, we can also ++ * automatically run _REG for the following case: ++ * operation_region (OPR1, 0x80, 0x1000010, 0x4) ++ * Though this may not be compliant to the de-facto standard, the ++ * logic is kept in order not to trigger regressions. And keeping ++ * this logic should be taken care by the caller of this function. ++ * + ******************************************************************************/ + +-acpi_status +-acpi_ev_initialize_region(union acpi_operand_object *region_obj, +- u8 acpi_ns_locked) ++acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj) + { + union acpi_operand_object *handler_obj; + union acpi_operand_object *obj_desc; + acpi_adr_space_type space_id; + struct acpi_namespace_node *node; +- acpi_status status; + +- ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); ++ ACPI_FUNCTION_TRACE(ev_initialize_region); + + if (!region_obj) { + return_ACPI_STATUS(AE_BAD_PARAMETER); +@@ -580,39 +588,17 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, + handler_obj, region_obj, + obj_desc)); + +- status = +- acpi_ev_attach_region(handler_obj, +- region_obj, +- acpi_ns_locked); ++ (void)acpi_ev_attach_region(handler_obj, ++ region_obj, FALSE); + + /* + * Tell all users that this region is usable by + * running the _REG method + */ +- if (acpi_ns_locked) { +- status = +- acpi_ut_release_mutex +- (ACPI_MTX_NAMESPACE); +- if (ACPI_FAILURE(status)) { +- return_ACPI_STATUS(status); +- } +- } +- + acpi_ex_exit_interpreter(); +- status = +- acpi_ev_execute_reg_method(region_obj, +- ACPI_REG_CONNECT); ++ (void)acpi_ev_execute_reg_method(region_obj, ++ ACPI_REG_CONNECT); + acpi_ex_enter_interpreter(); +- +- if (acpi_ns_locked) { +- status = +- acpi_ut_acquire_mutex +- (ACPI_MTX_NAMESPACE); +- if (ACPI_FAILURE(status)) { +- return_ACPI_STATUS(status); +- } +- } +- + return_ACPI_STATUS(AE_OK); + } + } +@@ -622,12 +608,15 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, + node = node->parent; + } + +- /* If we get here, there is no handler for this region */ +- ++ /* ++ * If we get here, there is no handler for this region. This is not ++ * fatal because many regions get created before a handler is installed ++ * for said region. ++ */ + ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, + "No handler for RegionType %s(%X) (RegionObj %p)\n", + acpi_ut_get_region_name(space_id), space_id, + region_obj)); + +- return_ACPI_STATUS(AE_NOT_EXIST); ++ return_ACPI_STATUS(AE_OK); + } +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch b/kernel/tools/cpupowertools/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch new file mode 100644 index 00000000..a248ba34 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch @@ -0,0 +1,34 @@ +From 124298bd03acebd9c9da29a794718aca31bec1f7 Mon Sep 17 00:00:00 2001 +From: Daniel Roschka +Date: Wed, 22 Feb 2017 15:17:29 -0700 +Subject: [PATCH] nvme: detect NVMe controller in recent MacBooks + +Adds support for detection of the NVMe controller found in the +following recent MacBooks: +- Retina MacBook 2016 (MacBook9,1) +- 13" MacBook Pro 2016 without Touch Bar (MacBook13,1) +- 13" MacBook Pro 2016 with Touch Bar (MacBook13,2) + +Signed-off-by: Daniel Roschka +Reviewed-by: Christoph Hellwig +Signed-off-by: Sagi Grimberg +Signed-off-by: Jens Axboe +--- + drivers/nvme/host/pci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index d38dae9..319f5c5 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2120,6 +2120,7 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, }, + { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, + { 0, } + }; + MODULE_DEVICE_TABLE(pci, nvme_id_table); +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch new file mode 100644 index 00000000..3a010204 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch @@ -0,0 +1,38 @@ +From fc8e9c54699e42754094ff475da46440778d8f19 Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Thu, 4 Aug 2016 12:54:22 +0800 +Subject: [PATCH] drm/amd/amdgpu: add Polaris12 PCI ID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index 8cb937b..2534ada 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -418,6 +418,13 @@ static const struct pci_device_id pciidlist[] = { + {0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, ++ /* Polaris12 */ ++ {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, ++ {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + + {0, 0, 0} + }; +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch new file mode 100644 index 00000000..7b8a1133 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch @@ -0,0 +1,469 @@ +From c4642a479fac9f5c224ff7425d86c427b94011af Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Wed, 14 Dec 2016 15:32:28 -0500 +Subject: [PATCH] drm/amd/amdgpu: add Polaris12 support (v3) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +v2: agd: squash in various fixes +v3: agd: squash in: +drm/amdgpu: remove unnecessary smc sk firmware for polaris12 + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +[ rebased for 4.9 / tmb ] +Signed-off-by: Thomas Backlund +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c | 3 +++ + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 ++ + drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 13 ++++++++++--- + drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 31 +++++++++++++++++++++++++----- + drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 5 +++++ + drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 6 ++++++ + drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 5 +++-- + drivers/gpu/drm/amd/amdgpu/vi.c | 10 ++++++++++ + drivers/gpu/drm/amd/include/amd_shared.h | 1 + + 11 files changed, 76 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +index 9ada56c..4c851fde 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +@@ -840,6 +840,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, + else if (type == CGS_UCODE_ID_SMU_SK) + strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin"); + break; ++ case CHIP_POLARIS12: ++ strcpy(fw_name, "amdgpu/polaris12_smc.bin"); ++ break; + default: + DRM_ERROR("SMC firmware not supported\n"); + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index 60bd4af..fe3bb94 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -73,6 +73,7 @@ static const char *amdgpu_asic_name[] = { + "STONEY", + "POLARIS10", + "POLARIS11", ++ "POLARIS12", + "LAST", + }; + +@@ -1277,6 +1278,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev) + case CHIP_FIJI: + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_CARRIZO: + case CHIP_STONEY: + if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY) +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +index a81dfae..1d564be 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +@@ -65,6 +65,7 @@ + #define FIRMWARE_STONEY "amdgpu/stoney_uvd.bin" + #define FIRMWARE_POLARIS10 "amdgpu/polaris10_uvd.bin" + #define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin" ++#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin" + + /** + * amdgpu_uvd_cs_ctx - Command submission parser context +@@ -98,6 +99,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); + MODULE_FIRMWARE(FIRMWARE_STONEY); + MODULE_FIRMWARE(FIRMWARE_POLARIS10); + MODULE_FIRMWARE(FIRMWARE_POLARIS11); ++MODULE_FIRMWARE(FIRMWARE_POLARIS12); + + static void amdgpu_uvd_idle_work_handler(struct work_struct *work); + +@@ -149,6 +151,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) + case CHIP_POLARIS11: + fw_name = FIRMWARE_POLARIS11; + break; ++ case CHIP_POLARIS12: ++ fw_name = FIRMWARE_POLARIS12; ++ break; + default: + return -EINVAL; + } +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +index 69b66b9..8fec802 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +@@ -52,6 +52,7 @@ + #define FIRMWARE_STONEY "amdgpu/stoney_vce.bin" + #define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin" + #define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin" ++#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin" + + #ifdef CONFIG_DRM_AMDGPU_CIK + MODULE_FIRMWARE(FIRMWARE_BONAIRE); +@@ -66,6 +67,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); + MODULE_FIRMWARE(FIRMWARE_STONEY); + MODULE_FIRMWARE(FIRMWARE_POLARIS10); + MODULE_FIRMWARE(FIRMWARE_POLARIS11); ++MODULE_FIRMWARE(FIRMWARE_POLARIS12); + + static void amdgpu_vce_idle_work_handler(struct work_struct *work); + +@@ -121,6 +123,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) + case CHIP_POLARIS11: + fw_name = FIRMWARE_POLARIS11; + break; ++ case CHIP_POLARIS12: ++ fw_name = FIRMWARE_POLARIS12; ++ break; + + default: + return -EINVAL; +diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +index b3d62b9..2006abb 100644 +--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +@@ -167,6 +167,7 @@ static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(stoney_golden_settings_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + polaris11_golden_settings_a11, + (const u32)ARRAY_SIZE(polaris11_golden_settings_a11)); +@@ -608,6 +609,7 @@ static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev) + num_crtc = 6; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + num_crtc = 5; + break; + default: +@@ -1589,6 +1591,7 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev) + adev->mode_info.audio.num_pins = 8; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + adev->mode_info.audio.num_pins = 6; + break; + default: +@@ -2388,7 +2391,8 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc) + int pll; + + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + struct amdgpu_encoder *amdgpu_encoder = + to_amdgpu_encoder(amdgpu_crtc->encoder); + struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; +@@ -2822,7 +2826,8 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc, + return -EINVAL; + + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + struct amdgpu_encoder *amdgpu_encoder = + to_amdgpu_encoder(amdgpu_crtc->encoder); + int encoder_mode = +@@ -2992,6 +2997,7 @@ static int dce_v11_0_early_init(void *handle) + adev->mode_info.num_dig = 6; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + adev->mode_info.num_hpd = 5; + adev->mode_info.num_dig = 5; + break; +@@ -3101,7 +3107,8 @@ static int dce_v11_0_hw_init(void *handle) + amdgpu_atombios_crtc_powergate_init(adev); + amdgpu_atombios_encoder_init_dig(adev); + if ((adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) { ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) { + amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk, + DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS); + amdgpu_atombios_crtc_set_dce_clock(adev, 0, +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +index d0ec009..3733741 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +@@ -138,6 +138,13 @@ MODULE_FIRMWARE("amdgpu/polaris10_mec.bi + MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin"); + ++MODULE_FIRMWARE("amdgpu/polaris12_ce.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_me.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mec.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin"); ++ + static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] = + { + {mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0}, +@@ -687,6 +694,7 @@ static void gfx_v8_0_init_golden_registe + (const u32)ARRAY_SIZE(tonga_golden_common_all)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -901,6 +909,9 @@ static int gfx_v8_0_init_microcode(struc + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_STONEY: + chip_name = "stoney"; + break; +@@ -1777,6 +1788,7 @@ static int gfx_v8_0_gpu_early_init(struc + gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + ret = amdgpu_atombios_get_gfx_info(adev); + if (ret) + return ret; +@@ -2695,6 +2707,7 @@ static void gfx_v8_0_tiling_mode_table_i + + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | +@@ -3516,6 +3529,7 @@ gfx_v8_0_raster_config(struct amdgpu_dev + *rconf1 |= 0x0; + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) | + SE_XSEL(1) | SE_YSEL(1); + *rconf1 |= 0x0; +@@ -4029,7 +4043,8 @@ static void gfx_v8_0_init_pg(struct amdg + cz_enable_cp_power_gating(adev, true); + else + cz_enable_cp_power_gating(adev, false); +- } else if (adev->asic_type == CHIP_POLARIS11) { ++ } else if ((adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS11)) { + gfx_v8_0_init_power_gating(adev); + } + } +@@ -4100,7 +4115,8 @@ static int gfx_v8_0_rlc_resume(struct am + RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK); + WREG32(mmRLC_CGCG_CGLS_CTRL, tmp); + if (adev->asic_type == CHIP_POLARIS11 || +- adev->asic_type == CHIP_POLARIS10) { ++ adev->asic_type == CHIP_POLARIS10 || ++ adev->asic_type == CHIP_POLARIS12) { + tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D); + tmp &= ~0x3; + WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp); +@@ -4288,6 +4304,7 @@ static int gfx_v8_0_cp_gfx_start(struct + amdgpu_ring_write(ring, 0x0000002A); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_ring_write(ring, 0x16000012); + amdgpu_ring_write(ring, 0x00000000); + break; +@@ -4938,7 +4955,8 @@ static int gfx_v8_0_cp_compute_resume(st + (adev->asic_type == CHIP_FIJI) || + (adev->asic_type == CHIP_STONEY) || + (adev->asic_type == CHIP_POLARIS11) || +- (adev->asic_type == CHIP_POLARIS10)) { ++ (adev->asic_type == CHIP_POLARIS10) || ++ (adev->asic_type == CHIP_POLARIS12)) { + WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, + AMDGPU_DOORBELL_KIQ << 2); + WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, +@@ -4974,7 +4992,8 @@ static int gfx_v8_0_cp_compute_resume(st + mqd->cp_hqd_persistent_state = tmp; + if (adev->asic_type == CHIP_STONEY || + adev->asic_type == CHIP_POLARIS11 || +- adev->asic_type == CHIP_POLARIS10) { ++ adev->asic_type == CHIP_POLARIS10 || ++ adev->asic_type == CHIP_POLARIS12) { + tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL); + tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1); + WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp); +@@ -5488,7 +5507,8 @@ static int gfx_v8_0_late_init(void *hand + static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, + bool enable) + { +- if (adev->asic_type == CHIP_POLARIS11) ++ if ((adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) + /* Send msg to SMU via Powerplay */ + amdgpu_set_powergating_state(adev, + AMD_IP_BLOCK_TYPE_SMC, +@@ -5565,6 +5585,7 @@ static int gfx_v8_0_set_powergating_stat + gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable) + gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true); + else +diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +index 0daac3a..476bc9f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +@@ -46,6 +46,7 @@ static int gmc_v8_0_wait_for_idle(void *handle); + MODULE_FIRMWARE("amdgpu/tonga_mc.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_mc.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_mc.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_mc.bin"); + + static const u32 golden_settings_tonga_a11[] = + { +@@ -130,6 +131,7 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -225,6 +227,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_FIJI: + case CHIP_CARRIZO: + case CHIP_STONEY: +diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +index 1170a64..034ace7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +@@ -60,6 +60,8 @@ MODULE_FIRMWARE("amdgpu/polaris10_sdma.bin"); + MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin"); + + + static const u32 sdma_offsets[SDMA_MAX_INSTANCE] = +@@ -206,6 +208,7 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev) + (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); + break; + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + amdgpu_program_register_sequence(adev, + golden_settings_polaris11_a11, + (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); +@@ -278,6 +281,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) + case CHIP_POLARIS10: + chip_name = "polaris10"; + break; ++ case CHIP_POLARIS12: ++ chip_name = "polaris12"; ++ break; + case CHIP_CARRIZO: + chip_name = "carrizo"; + break; +diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +index 6b3293a..5fb0b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +@@ -320,11 +320,12 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) + { + u32 tmp; + +- /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ ++ /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */ + if ((adev->asic_type == CHIP_FIJI) || + (adev->asic_type == CHIP_STONEY) || + (adev->asic_type == CHIP_POLARIS10) || +- (adev->asic_type == CHIP_POLARIS11)) ++ (adev->asic_type == CHIP_POLARIS11) || ++ (adev->asic_type == CHIP_POLARIS12)) + return AMDGPU_VCE_HARVEST_VCE1; + + /* Tonga and CZ are dual or single pipe */ +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index bf088d6..c2ac54f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -88,6 +88,7 @@ MODULE_FIRMWARE("amdgpu/polaris10_smc.bi + MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_smc.bin"); + MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin"); ++MODULE_FIRMWARE("amdgpu/polaris12_smc.bin"); + + /* + * Indirect registers accessor +@@ -312,6 +313,7 @@ static void vi_init_golden_registers(str + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + default: + break; + } +@@ -592,6 +594,7 @@ static int vi_read_register(struct amdgp + case CHIP_TONGA: + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_CARRIZO: + case CHIP_STONEY: + asic_register_table = cz_allowed_read_registers; +@@ -1465,6 +1468,7 @@ int vi_set_ip_blocks(struct amdgpu_devic + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + adev->ip_blocks = polaris11_ip_blocks_vd; + adev->num_ip_blocks = ARRAY_SIZE(polaris11_ip_blocks_vd); + break; +@@ -1608,6 +1612,11 @@ static int vi_common_early_init(void *ha + adev->pg_flags = 0; + adev->external_rev_id = adev->rev_id + 0x50; + break; ++ case CHIP_POLARIS12: ++ adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG; ++ adev->pg_flags = 0; ++ adev->external_rev_id = adev->rev_id + 0x64; ++ break; + case CHIP_CARRIZO: + adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG | + AMD_CG_SUPPORT_GFX_MGCG | +@@ -1897,6 +1906,7 @@ static int vi_common_set_clockgating_sta + case CHIP_TONGA: + case CHIP_POLARIS10: + case CHIP_POLARIS11: ++ case CHIP_POLARIS12: + vi_common_set_clockgating_state_by_smu(adev, state); + default: + break; +diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h +index c02469a..5f59117 100644 +--- a/drivers/gpu/drm/amd/include/amd_shared.h ++++ b/drivers/gpu/drm/amd/include/amd_shared.h +@@ -46,6 +46,7 @@ enum amd_asic_type { + CHIP_STONEY, + CHIP_POLARIS10, + CHIP_POLARIS11, ++ CHIP_POLARIS12, + CHIP_LAST, + }; + +-- +2.10.2 diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch new file mode 100644 index 00000000..de592904 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch @@ -0,0 +1,32 @@ +From c10c8f7c27103bd7ac02d041d9d6e97296d48fc1 Mon Sep 17 00:00:00 2001 +From: Alex Deucher +Date: Fri, 10 Feb 2017 18:09:32 -0500 +Subject: [PATCH] drm/amdgpu/pm: check for headless before calling + compute_clocks + +Don't update display bandwidth on headless asics. + +bug: +https://bugs.freedesktop.org/show_bug.cgi?id=99387 + +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +index 95e026a..346e80a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +@@ -1283,7 +1283,9 @@ void amdgpu_pm_compute_clocks(struct amd + if (adev->pp_enabled) { + int i = 0; + +- amdgpu_display_bandwidth_update(adev); ++ if (adev->mode_info.num_crtc) ++ amdgpu_display_bandwidth_update(adev); ++ + for (i = 0; i < AMDGPU_MAX_RINGS; i++) { + struct amdgpu_ring *ring = adev->rings[i]; + if (ring && ring->ready) diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch new file mode 100644 index 00000000..7b2b0f63 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch @@ -0,0 +1,81 @@ +From f4309526576db325264b6dc9ee150ee70b330a42 Mon Sep 17 00:00:00 2001 +From: Junwei Zhang +Date: Wed, 14 Dec 2016 15:40:48 -0500 +Subject: [PATCH] drm/amdgpu/powerplay: add Polaris12 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Junwei Zhang +Reviewed-by: Alex Deucher +Reviewed-by: Christian König +Reviewed-by: Ken Wang +Signed-off-by: Alex Deucher +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c | 1 + + drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 3 ++- + drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c | 2 +- + drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c | 1 + + 4 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +index fc592c2..95a568d 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +@@ -98,6 +98,7 @@ static int amdgpu_pp_early_init(void *handle) + switch (adev->asic_type) { + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + case CHIP_TONGA: + case CHIP_FIJI: + case CHIP_TOPAZ: +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +index dc6700a..b036064 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +@@ -95,6 +95,7 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + polaris_set_asic_special_caps(hwmgr); + hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK); + break; +@@ -745,7 +746,7 @@ int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_TablelessHardwareInterface); + +- if (hwmgr->chip_id == CHIP_POLARIS11) ++ if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) + phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_SPLLShutdownSupport); + return 0; +diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +index 26477f0..6cd1287 100644 +--- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c ++++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +@@ -521,7 +521,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr) + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); + result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10); + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); +- } else if (hwmgr->chip_id == CHIP_POLARIS11) { ++ } else if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) { + result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11); + PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); + result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11); +diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +index e5812aa..6e618aa 100644 +--- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c ++++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +@@ -65,6 +65,7 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle) + break; + case CHIP_POLARIS11: + case CHIP_POLARIS10: ++ case CHIP_POLARIS12: + polaris10_smum_init(smumgr); + break; + default: +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch deleted file mode 100644 index 7a90bae2..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 8726f2faa371514fba2f594d799db95203dfeee0 Mon Sep 17 00:00:00 2001 -From: Francisco Jerez -Date: Thu, 12 Jan 2017 12:44:54 +0200 -Subject: drm/i915: Remove WaDisableLSQCROPERFforOCL KBL workaround. - -The WaDisableLSQCROPERFforOCL workaround has the side effect of -disabling an L3SQ optimization that has huge performance implications -and is unlikely to be necessary for the correct functioning of usual -graphic workloads. Userspace is free to re-enable the workaround on -demand, and is generally in a better position to determine whether the -workaround is necessary than the DRM is (e.g. only during the -execution of compute kernels that rely on both L3 fences and HDC R/W -requests). - -The same workaround seems to apply to BDW (at least to production -stepping G1) and SKL as well (the internal workaround database claims -that it does for all steppings, while the BSpec workaround table only -mentions pre-production steppings), but the DRM doesn't do anything -beyond whitelisting the L3SQCREG4 register so userspace can enable it -when it sees fit. Do the same on KBL platforms. - -Improves performance of the GFXBench4 gl_manhattan31 benchmark by 60%, -and gl_4 (AKA car chase) by 14% on a KBL GT2 running Mesa master -- -This is followed by a regression of 35% and 10% respectively for the -same benchmarks and platform caused by my recent patch series -switching userspace to use the dataport constant cache instead of the -sampler to implement uniform pull constant loads, which caused us to -hit more heavily the L3 cache (and on platforms other than KBL had the -opposite effect of improving performance of the same two benchmarks). -The overall effect on KBL of this change combined with the recent -userspace change is respectively 4.6% and 2.6%. SynMark2 OglShMapPcf -was affected by the constant cache changes (though it improved as it -did on other platforms rather than regressing), but is not -significantly affected by this patch (with statistical significance of -5% and sample size 20). - -v2: Drop some more code to avoid unused variable warning. - -Fixes: 738fa1b3123f ("drm/i915/kbl: Add WaDisableLSQCROPERFforOCL") -Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99256 -Signed-off-by: Francisco Jerez -Cc: Matthew Auld -Cc: Eero Tamminen -Cc: Jani Nikula -Cc: Mika Kuoppala -Cc: beignet@lists.freedesktop.org -Cc: # v4.7+ -Reviewed-by: Mika Kuoppala -[Removed double Fixes tag] -Signed-off-by: Mika Kuoppala -Link: http://patchwork.freedesktop.org/patch/msgid/1484217894-20505-1-git-send-email-mika.kuoppala@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index db714dc..8acab87 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -970,18 +970,8 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, - uint32_t *batch, - uint32_t index) - { -- struct drm_i915_private *dev_priv = engine->i915; - uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - -- /* -- * WaDisableLSQCROPERFforOCL:kbl -- * This WA is implemented in skl_init_clock_gating() but since -- * this batch updates GEN8_L3SQCREG4 with default value we need to -- * set this bit here to retain the WA during flush. -- */ -- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -- l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; -- - wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index ab83fc2..49fa800 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1095,14 +1095,6 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE); - -- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes -- * involving this register should also be added to WA batch as required. -- */ -- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -- /* WaDisableLSQCROPERFforOCL:kbl */ -- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- GEN8_LQSC_RO_PERF_DIS); -- - /* WaToEnableHwFixForPushConstHWBug:kbl */ - if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) - WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, --- -cgit v0.10.2 - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch new file mode 100644 index 00000000..aaf9bb26 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch @@ -0,0 +1,42 @@ +From 853277481178fdf14d1a4e9e6ac7174d6046176f Mon Sep 17 00:00:00 2001 +From: Jani Nikula +Date: Wed, 1 Feb 2017 15:46:09 +0200 +Subject: [PATCH] drm/i915: don't warn about Skylake CPU - KabyPoint PCH combo + +Apparently there are machines out there with Skylake CPU and KabyPoint +PCH. Judging from our driver code, there doesn't seem to be any code +paths that would do anything different between SunrisePoint and +KabyPoint PCHs, so it would seem okay to accept the combo without +warnings. + +Fixes: 22dea0be50b2 ("drm/i915: Introduce Kabypoint PCH for Kabylake H/DT.") +References: https://lists.freedesktop.org/archives/intel-gfx/2017-February/118611.html +Reported-by: Rainer Koenig +Cc: Rainer Koenig +Cc: Rodrigo Vivi +Cc: # v4.8+ +Reviewed-by: Rodrigo Vivi +Signed-off-by: Jani Nikula +Link: http://patchwork.freedesktop.org/patch/msgid/1485956769-26015-1-git-send-email-jani.nikula@intel.com +(cherry picked from commit 3aac4acb89710fe782c9e78e7b1febf76e112c6c) +Signed-off-by: Jani Nikula +[ rebased for 4.9 / tmb ] +Signed-off-by: Thomas Backlund +--- + drivers/gpu/drm/i915/i915_drv.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c +index b2c4a0b..8d63098 100644 +--- a/drivers/gpu/drm/i915/i915_drv.c ++++ b/drivers/gpu/drm/i915/i915_drv.c +@@ -207,7 +207,8 @@ static void intel_detect_pch(struct drm_ + } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { + dev_priv->pch_type = PCH_KBP; + DRM_DEBUG_KMS("Found KabyPoint PCH\n"); +- WARN_ON(!IS_KABYLAKE(dev)); ++ WARN_ON(!IS_SKYLAKE(dev) && ++ !IS_KABYLAKE(dev)); + } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || + (id == INTEL_PCH_P3X_DEVICE_ID_TYPE) || + ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch deleted file mode 100644 index 8cdf7198..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch +++ /dev/null @@ -1,127 +0,0 @@ -From a117f378f44150e6d13d2f19740fb757425b651f Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:44 +0300 -Subject: drm/i915/skl: drop workarounds for A0 and B0 revisions - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/7929af62a68504c84038a8db1625bd96ebaa9e6f.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c -index 0568fb5..57da2b7 100644 ---- a/drivers/gpu/drm/i915/intel_dp.c -+++ b/drivers/gpu/drm/i915/intel_dp.c -@@ -1299,10 +1299,6 @@ bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp) - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - -- /* WaDisableHBR2:skl */ -- if (IS_SKL_REVID(dev, 0, SKL_REVID_B0)) -- return false; -- - if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || - (INTEL_INFO(dev)->gen >= 9)) - return true; -diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c -index c438b02..0048b52 100644 ---- a/drivers/gpu/drm/i915/intel_dp_link_training.c -+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c -@@ -225,9 +225,6 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp) - * Intel platforms that support HBR2 also support TPS3. TPS3 support is - * also mandatory for downstream devices that support HBR2. However, not - * all sinks follow the spec. -- * -- * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is -- * supported in source but still not enabled. - */ - source_tps3 = intel_dp_source_supports_hbr2(intel_dp); - sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd); -diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c -index 6fd39ef..acc1dbd 100644 ---- a/drivers/gpu/drm/i915/intel_guc_loader.c -+++ b/drivers/gpu/drm/i915/intel_guc_loader.c -@@ -375,9 +375,8 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv) - /* Enable MIA caching. GuC clock gating is disabled. */ - I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); - -- /* WaDisableMinuteIaClockGating:skl,bxt */ -- if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { -+ /* WaDisableMinuteIaClockGating:bxt */ -+ if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { - I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) & - ~GUC_ENABLE_MIA_CLOCK_GATING)); - } -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index 39417b7..47f7afa 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -269,8 +269,7 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine) - struct drm_i915_private *dev_priv = engine->i915; - - engine->disable_lite_restore_wa = -- (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) && -+ IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1) && - (engine->id == VCS || engine->id == VCS2); - - engine->ctx_desc_template = GEN8_CTX_VALID; -@@ -1068,9 +1067,8 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *engine, - { - uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - -- /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ -- if (IS_SKL_REVID(engine->i915, 0, SKL_REVID_B0) || -- IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) { -+ /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:bxt */ -+ if (IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) { - wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); - wa_ctx_emit(batch, index, -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 7a74750..2faf64f 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -851,15 +851,13 @@ static int gen9_init_workarounds(struct intel_engine_cs *engine) - WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, - GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); - -- /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) -+ /* WaDisableDgMirrorFixInHalfSliceChicken5:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) - WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, - GEN9_DG_MIRROR_FIX_ENABLE); - -- /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { -+ /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { - WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, - GEN9_RHWO_OPTIMIZATION_DISABLE); - /* -@@ -1023,15 +1021,8 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - GEN8_LQSC_RO_PERF_DIS); - - /* WaEnableGapsTsvCreditFix:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, REVID_FOREVER)) { -- I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | -- GEN9_GAPS_TSV_CREDIT_DISABLE)); -- } -- -- /* WaDisablePowerCompilerClockGating:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_B0, SKL_REVID_B0)) -- WA_SET_BIT_MASKED(HIZ_CHICKEN, -- BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); -+ I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | -+ GEN9_GAPS_TSV_CREDIT_DISABLE)); - - /* WaBarrierPerformanceFixDisable:skl */ - if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0)) --- -cgit v0.10.2 - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch deleted file mode 100644 index 0643ccd9..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 9fc736e833d226853fd53843e35d6a1d542394ed Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:46 +0300 -Subject: drm/i915/skl: drop workarounds for D0 revision - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/d28d21ceddeec226b5d1a20a7382bee9a72709a4.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index 47f7afa..ca649cc 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -994,9 +994,8 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *engine, - struct drm_i915_private *dev_priv = engine->i915; - uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - -- /* WaDisableCtxRestoreArbitration:skl,bxt */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_D0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) -+ /* WaDisableCtxRestoreArbitration:bxt */ -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) - wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); - - /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ -@@ -1095,9 +1094,8 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *engine, - wa_ctx_emit(batch, index, MI_NOOP); - } - -- /* WaDisableCtxRestoreArbitration:skl,bxt */ -- if (IS_SKL_REVID(engine->i915, 0, SKL_REVID_D0) || -- IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) -+ /* WaDisableCtxRestoreArbitration:bxt */ -+ if (IS_BXT_REVID(engine->i915, 0, BXT_REVID_A1)) - wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); - - wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); -diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c -index 2df06b7..a860c40 100644 ---- a/drivers/gpu/drm/i915/intel_pm.c -+++ b/drivers/gpu/drm/i915/intel_pm.c -@@ -5335,8 +5335,7 @@ static void gen9_enable_rc6(struct drm_i915_private *dev_priv) - rc6_mask = GEN6_RC_CTL_RC6_ENABLE; - DRM_INFO("RC6 %s\n", onoff(rc6_mask & GEN6_RC_CTL_RC6_ENABLE)); - /* WaRsUseTimeoutMode */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_D0) || -- IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { -+ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { - I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */ - I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | - GEN7_RC_CTL_TO_MODE | -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 474ce84..6880082 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1000,10 +1000,8 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - * until D0 which is the default case so this is equivalent to - * !WaDisablePerCtxtPreemptionGranularityControl:skl - */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_E0, REVID_FOREVER)) { -- I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, -- _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); -- } -+ I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, -+ _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - - if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) { - /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ -@@ -1023,12 +1021,6 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); - -- /* WaBarrierPerformanceFixDisable:skl */ -- if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0)) -- WA_SET_BIT_MASKED(HDC_CHICKEN0, -- HDC_FENCE_DEST_SLM_DISABLE | -- HDC_BARRIER_PERFORMANCE_DISABLE); -- - /* WaDisableSbeCacheDispatchPortSharing:skl */ - if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0)) - WA_SET_BIT_MASKED( --- -cgit v0.10.2 - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch b/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch deleted file mode 100644 index 1c8f8a38..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 3be192e92ddcad15f7bf6b4b9e3f195eb8c1fe76 Mon Sep 17 00:00:00 2001 -From: Jani Nikula -Date: Fri, 16 Sep 2016 16:59:47 +0300 -Subject: drm/i915/skl: drop workarounds for E0 revision - -Pre-production hardware is not supported. - -Reviewed-by: Paulo Zanoni -Signed-off-by: Jani Nikula -Link: http://patchwork.freedesktop.org/patch/msgid/0633a02177195703502ef2396aab03efc0314334.1474034059.git.jani.nikula@intel.com - -diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c -index ca649cc..2d8eb2e 100644 ---- a/drivers/gpu/drm/i915/intel_lrc.c -+++ b/drivers/gpu/drm/i915/intel_lrc.c -@@ -845,13 +845,12 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, - uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - - /* -- * WaDisableLSQCROPERFforOCL:skl,kbl -+ * WaDisableLSQCROPERFforOCL:kbl - * This WA is implemented in skl_init_clock_gating() but since - * this batch updates GEN8_L3SQCREG4 with default value we need to - * set this bit here to retain the WA during flush. - */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0) || -- IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) -+ if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) - l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; - - wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | -diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c -index 6880082..68dc27f 100644 ---- a/drivers/gpu/drm/i915/intel_ringbuffer.c -+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c -@@ -1003,20 +1003,6 @@ static int skl_init_workarounds(struct intel_engine_cs *engine) - I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, - _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); - -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) { -- /* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */ -- I915_WRITE(FF_SLICE_CS_CHICKEN2, -- _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE)); -- } -- -- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes -- * involving this register should also be added to WA batch as required. -- */ -- if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) -- /* WaDisableLSQCROPERFforOCL:skl */ -- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- GEN8_LQSC_RO_PERF_DIS); -- - /* WaEnableGapsTsvCreditFix:skl */ - I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | - GEN9_GAPS_TSV_CREDIT_DISABLE)); --- -cgit v0.10.2 - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/net-wireguard.patch b/kernel/tools/cpupowertools/files/patches/mageia/net-wireguard.patch new file mode 100644 index 00000000..32c29f79 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/net-wireguard.patch @@ -0,0 +1,11839 @@ +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/config.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,321 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "config.h" ++#include "device.h" ++#include "socket.h" ++#include "packets.h" ++#include "timers.h" ++#include "hashtables.h" ++#include "peer.h" ++#include "uapi.h" ++ ++static int clear_peer_endpoint_src(struct wireguard_peer *peer, void *data) ++{ ++ socket_clear_peer_endpoint_src(peer); ++ return 0; ++} ++ ++static int set_device_port(struct wireguard_device *wg, u16 port) ++{ ++ socket_uninit(wg); ++ wg->incoming_port = port; ++ if (!(netdev_pub(wg)->flags & IFF_UP)) ++ return 0; ++ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL); ++ return socket_init(wg); ++} ++ ++static int set_ipmask(struct wireguard_peer *peer, void __user *user_ipmask) ++{ ++ int ret = -EINVAL; ++ struct wgipmask in_ipmask; ++ ++ if (copy_from_user(&in_ipmask, user_ipmask, sizeof(in_ipmask))) ++ return -EFAULT; ++ ++ if (in_ipmask.family == AF_INET && in_ipmask.cidr <= 32) ++ ret = routing_table_insert_v4(&peer->device->peer_routing_table, &in_ipmask.ip4, in_ipmask.cidr, peer); ++ else if (in_ipmask.family == AF_INET6 && in_ipmask.cidr <= 128) ++ ret = routing_table_insert_v6(&peer->device->peer_routing_table, &in_ipmask.ip6, in_ipmask.cidr, peer); ++ ++ return ret; ++} ++ ++static const u8 zeros[WG_KEY_LEN] = { 0 }; ++ ++static int set_peer(struct wireguard_device *wg, void __user *user_peer, size_t *len) ++{ ++ int ret = 0; ++ size_t i; ++ struct wgpeer in_peer; ++ void __user *user_ipmask; ++ struct wireguard_peer *peer = NULL; ++ ++ if (copy_from_user(&in_peer, user_peer, sizeof(in_peer))) ++ return -EFAULT; ++ ++ if (!memcmp(zeros, in_peer.public_key, NOISE_PUBLIC_KEY_LEN)) ++ return -EINVAL; /* Can't add a peer with no public key. */ ++ ++ peer = pubkey_hashtable_lookup(&wg->peer_hashtable, in_peer.public_key); ++ if (!peer) { /* Peer doesn't exist yet. Add a new one. */ ++ if (in_peer.flags & WGPEER_REMOVE_ME) ++ return -ENODEV; /* Tried to remove a non existing peer. */ ++ peer = peer_rcu_get(peer_create(wg, in_peer.public_key)); ++ if (!peer) ++ return -ENOMEM; ++ if (netdev_pub(wg)->flags & IFF_UP) ++ timers_init_peer(peer); ++ } ++ ++ if (in_peer.flags & WGPEER_REMOVE_ME) { ++ peer_put(peer); ++ peer_remove(peer); ++ goto out; ++ } ++ ++ if (in_peer.endpoint.addr.sa_family == AF_INET || in_peer.endpoint.addr.sa_family == AF_INET6) { ++ struct endpoint endpoint = { 0 }; ++ memcpy(&endpoint, &in_peer.endpoint, sizeof(in_peer.endpoint)); ++ socket_set_peer_endpoint(peer, &endpoint); ++ } ++ ++ if (in_peer.flags & WGPEER_REPLACE_IPMASKS) ++ routing_table_remove_by_peer(&wg->peer_routing_table, peer); ++ for (i = 0, user_ipmask = user_peer + sizeof(struct wgpeer); i < in_peer.num_ipmasks; ++i, user_ipmask += sizeof(struct wgipmask)) { ++ ret = set_ipmask(peer, user_ipmask); ++ if (ret) ++ break; ++ } ++ ++ if (in_peer.persistent_keepalive_interval != (u16)-1) { ++ const bool send_keepalive = !peer->persistent_keepalive_interval && in_peer.persistent_keepalive_interval && netdev_pub(wg)->flags & IFF_UP; ++ peer->persistent_keepalive_interval = (unsigned long)in_peer.persistent_keepalive_interval * HZ; ++ if (send_keepalive) ++ packet_send_keepalive(peer); ++ } ++ ++ if (netdev_pub(wg)->flags & IFF_UP) ++ packet_send_queue(peer); ++ ++ peer_put(peer); ++ ++out: ++ if (!ret) ++ *len = sizeof(struct wgpeer) + (in_peer.num_ipmasks * sizeof(struct wgipmask)); ++ ++ return ret; ++} ++ ++int config_set_device(struct wireguard_device *wg, void __user *user_device) ++{ ++ int ret = 0; ++ size_t i, offset; ++ struct wgdevice in_device; ++ void __user *user_peer; ++ bool modified_static_identity = false; ++ ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); ++ ++ mutex_lock(&wg->device_update_lock); ++ ++ if (copy_from_user(&in_device, user_device, sizeof(in_device))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (in_device.fwmark || (!in_device.fwmark && (in_device.flags & WGDEVICE_REMOVE_FWMARK))) { ++ wg->fwmark = in_device.fwmark; ++ peer_for_each_unlocked(wg, clear_peer_endpoint_src, NULL); ++ } ++ ++ if (in_device.port) { ++ ret = set_device_port(wg, in_device.port); ++ if (ret) ++ goto out; ++ } ++ ++ if (in_device.flags & WGDEVICE_REPLACE_PEERS) ++ peer_remove_all(wg); ++ ++ if (in_device.flags & WGDEVICE_REMOVE_PRIVATE_KEY) { ++ noise_set_static_identity_private_key(&wg->static_identity, NULL); ++ modified_static_identity = true; ++ } else if (memcmp(zeros, in_device.private_key, WG_KEY_LEN)) { ++ noise_set_static_identity_private_key(&wg->static_identity, in_device.private_key); ++ modified_static_identity = true; ++ } ++ ++ if (in_device.flags & WGDEVICE_REMOVE_PRESHARED_KEY) { ++ noise_set_static_identity_preshared_key(&wg->static_identity, NULL); ++ modified_static_identity = true; ++ } else if (memcmp(zeros, in_device.preshared_key, WG_KEY_LEN)) { ++ noise_set_static_identity_preshared_key(&wg->static_identity, in_device.preshared_key); ++ modified_static_identity = true; ++ } ++ ++ if (modified_static_identity) ++ cookie_checker_precompute_keys(&wg->cookie_checker, NULL); ++ ++ for (i = 0, offset = 0, user_peer = user_device + sizeof(struct wgdevice); i < in_device.num_peers; ++i, user_peer += offset) { ++ ret = set_peer(wg, user_peer, &offset); ++ if (ret) ++ break; ++ } ++ ++out: ++ mutex_unlock(&wg->device_update_lock); ++ memzero_explicit(&in_device.private_key, NOISE_PUBLIC_KEY_LEN); ++ return ret; ++} ++ ++struct data_remaining { ++ void __user *data; ++ size_t out_len; ++ size_t count; ++}; ++ ++static inline int use_data(struct data_remaining *data, size_t size) ++{ ++ if (data->out_len < size) ++ return -EMSGSIZE; ++ data->out_len -= size; ++ data->data += size; ++ ++data->count; ++ return 0; ++} ++ ++static int calculate_ipmasks_size(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family) ++{ ++ size_t *count = ctx; ++ *count += sizeof(struct wgipmask); ++ return 0; ++} ++ ++static size_t calculate_peers_size(struct wireguard_device *wg) ++{ ++ size_t len = peer_total_count(wg) * sizeof(struct wgpeer); ++ routing_table_walk_ips(&wg->peer_routing_table, &len, calculate_ipmasks_size); ++ return len; ++} ++ ++static int populate_ipmask(void *ctx, union nf_inet_addr ip, u8 cidr, int family) ++{ ++ int ret; ++ struct data_remaining *data = ctx; ++ void __user *uipmask = data->data; ++ struct wgipmask out_ipmask; ++ ++ memset(&out_ipmask, 0, sizeof(struct wgipmask)); ++ ++ ret = use_data(data, sizeof(struct wgipmask)); ++ if (ret) ++ return ret; ++ ++ out_ipmask.cidr = cidr; ++ out_ipmask.family = family; ++ if (family == AF_INET) ++ out_ipmask.ip4 = ip.in; ++ else if (family == AF_INET6) ++ out_ipmask.ip6 = ip.in6; ++ ++ if (copy_to_user(uipmask, &out_ipmask, sizeof(out_ipmask))) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ ++static int populate_peer(struct wireguard_peer *peer, void *ctx) ++{ ++ int ret = 0; ++ struct data_remaining *data = ctx; ++ void __user *upeer = data->data; ++ struct wgpeer out_peer; ++ struct data_remaining ipmasks_data = { NULL }; ++ ++ memset(&out_peer, 0, sizeof(struct wgpeer)); ++ ++ ret = use_data(data, sizeof(struct wgpeer)); ++ if (ret) ++ return ret; ++ ++ memcpy(out_peer.public_key, peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN); ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ out_peer.endpoint.addr4 = peer->endpoint.addr4; ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ out_peer.endpoint.addr6 = peer->endpoint.addr6; ++ read_unlock_bh(&peer->endpoint_lock); ++ out_peer.last_handshake_time = peer->walltime_last_handshake; ++ out_peer.tx_bytes = peer->tx_bytes; ++ out_peer.rx_bytes = peer->rx_bytes; ++ out_peer.persistent_keepalive_interval = (u16)(peer->persistent_keepalive_interval / HZ); ++ ++ ipmasks_data.out_len = data->out_len; ++ ipmasks_data.data = data->data; ++ ret = routing_table_walk_ips_by_peer_sleepable(&peer->device->peer_routing_table, &ipmasks_data, peer, populate_ipmask); ++ if (ret) ++ return ret; ++ data->out_len = ipmasks_data.out_len; ++ data->data = ipmasks_data.data; ++ out_peer.num_ipmasks = ipmasks_data.count; ++ ++ if (copy_to_user(upeer, &out_peer, sizeof(out_peer))) ++ ret = -EFAULT; ++ return ret; ++} ++ ++int config_get_device(struct wireguard_device *wg, void __user *udevice) ++{ ++ int ret = 0; ++ struct net_device *dev = netdev_pub(wg); ++ struct data_remaining peer_data = { NULL }; ++ struct wgdevice out_device; ++ struct wgdevice in_device; ++ ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); ++ BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); ++ ++ memset(&out_device, 0, sizeof(struct wgdevice)); ++ ++ mutex_lock(&wg->device_update_lock); ++ ++ if (!udevice) { ++ ret = calculate_peers_size(wg); ++ goto out; ++ } ++ ++ if (copy_from_user(&in_device, udevice, sizeof(in_device))) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ out_device.port = wg->incoming_port; ++ out_device.fwmark = wg->fwmark; ++ strncpy(out_device.interface, dev->name, IFNAMSIZ - 1); ++ out_device.interface[IFNAMSIZ - 1] = 0; ++ ++ down_read(&wg->static_identity.lock); ++ if (wg->static_identity.has_identity) { ++ memcpy(out_device.private_key, wg->static_identity.static_private, WG_KEY_LEN); ++ memcpy(out_device.public_key, wg->static_identity.static_public, WG_KEY_LEN); ++ memcpy(out_device.preshared_key, wg->static_identity.preshared_key, WG_KEY_LEN); ++ } ++ up_read(&wg->static_identity.lock); ++ ++ peer_data.out_len = in_device.peers_size; ++ peer_data.data = udevice + sizeof(struct wgdevice); ++ ret = peer_for_each_unlocked(wg, populate_peer, &peer_data); ++ if (ret) ++ goto out; ++ out_device.num_peers = peer_data.count; ++ ++ if (copy_to_user(udevice, &out_device, sizeof(out_device))) ++ ret = -EFAULT; ++ ++out: ++ mutex_unlock(&wg->device_update_lock); ++ memzero_explicit(&out_device.private_key, NOISE_PUBLIC_KEY_LEN); ++ return ret; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/cookie.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,215 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "cookie.h" ++#include "peer.h" ++#include "device.h" ++#include "messages.h" ++#include "crypto/blake2s.h" ++#include "crypto/chacha20poly1305.h" ++ ++#include ++#include ++#include ++ ++int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg) ++{ ++ int ret = ratelimiter_init(&checker->ratelimiter, wg); ++ if (ret) ++ return ret; ++ init_rwsem(&checker->secret_lock); ++ checker->secret_birthdate = get_jiffies_64(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ checker->device = wg; ++ return 0; ++} ++ ++static int precompute_peer_key(struct wireguard_peer *peer, void *psk) ++{ ++ blake2s(peer->latest_cookie.cookie_decryption_key, peer->handshake.remote_static, psk, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, psk ? NOISE_SYMMETRIC_KEY_LEN : 0); ++ return 0; ++} ++ ++void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer) ++{ ++ down_read(&checker->device->static_identity.lock); ++ if (unlikely(checker->device->static_identity.has_identity)) { ++ memset(checker->cookie_encryption_key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ goto out; ++ } ++ ++ if (peer) ++ precompute_peer_key(peer, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ else { ++ blake2s(checker->cookie_encryption_key, checker->device->static_identity.static_public, checker->device->static_identity.preshared_key, NOISE_SYMMETRIC_KEY_LEN, NOISE_PUBLIC_KEY_LEN, checker->device->static_identity.has_psk ? NOISE_SYMMETRIC_KEY_LEN : 0); ++ peer_for_each_unlocked(checker->device, precompute_peer_key, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ } ++ ++out: ++ up_read(&checker->device->static_identity.lock); ++} ++ ++void cookie_checker_uninit(struct cookie_checker *checker) ++{ ++ ratelimiter_uninit(&checker->ratelimiter); ++} ++ ++void cookie_init(struct cookie *cookie) ++{ ++ memset(cookie, 0, sizeof(struct cookie)); ++ init_rwsem(&cookie->lock); ++} ++ ++static void compute_mac1(u8 mac1[COOKIE_LEN], const void *message, size_t len, const u8 pubkey[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ struct blake2s_state state; ++ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac1); ++ ++ if (psk) ++ blake2s_init_key(&state, COOKIE_LEN, psk, NOISE_SYMMETRIC_KEY_LEN); ++ else ++ blake2s_init(&state, COOKIE_LEN); ++ blake2s_update(&state, pubkey, NOISE_PUBLIC_KEY_LEN); ++ blake2s_update(&state, message, len); ++ blake2s_final(&state, mac1, COOKIE_LEN); ++} ++ ++static void compute_mac2(u8 mac2[COOKIE_LEN], const void *message, size_t len, const u8 cookie[COOKIE_LEN]) ++{ ++ len = len - sizeof(struct message_macs) + offsetof(struct message_macs, mac2); ++ blake2s(mac2, message, cookie, COOKIE_LEN, len, COOKIE_LEN); ++} ++ ++static void make_cookie(u8 cookie[COOKIE_LEN], struct sk_buff *skb, struct cookie_checker *checker) ++{ ++ struct blake2s_state state; ++ ++ if (!time_is_after_jiffies64(checker->secret_birthdate + COOKIE_SECRET_MAX_AGE)) { ++ down_write(&checker->secret_lock); ++ checker->secret_birthdate = get_jiffies_64(); ++ get_random_bytes(checker->secret, NOISE_HASH_LEN); ++ up_write(&checker->secret_lock); ++ } ++ ++ down_read(&checker->secret_lock); ++ ++ blake2s_init_key(&state, COOKIE_LEN, checker->secret, NOISE_HASH_LEN); ++ if (ip_hdr(skb)->version == 4) ++ blake2s_update(&state, (u8 *)&ip_hdr(skb)->saddr, sizeof(struct in_addr)); ++ else if (ip_hdr(skb)->version == 6) ++ blake2s_update(&state, (u8 *)&ipv6_hdr(skb)->saddr, sizeof(struct in6_addr)); ++ blake2s_update(&state, (u8 *)&udp_hdr(skb)->source, sizeof(__be16)); ++ blake2s_final(&state, cookie, COOKIE_LEN); ++ ++ up_read(&checker->secret_lock); ++} ++ ++enum cookie_mac_state cookie_validate_packet(struct cookie_checker *checker, struct sk_buff *skb, void *data_start, size_t data_len, bool check_cookie) ++{ ++ u8 computed_mac[COOKIE_LEN]; ++ u8 cookie[COOKIE_LEN]; ++ enum cookie_mac_state ret; ++ struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs)); ++ ++ ret = INVALID_MAC; ++ down_read(&checker->device->static_identity.lock); ++ if (unlikely(!checker->device->static_identity.has_identity)) { ++ up_read(&checker->device->static_identity.lock); ++ goto out; ++ } ++ compute_mac1(computed_mac, data_start, data_len, checker->device->static_identity.static_public, checker->device->static_identity.has_psk ? checker->device->static_identity.preshared_key : NULL); ++ up_read(&checker->device->static_identity.lock); ++ if (crypto_memneq(computed_mac, macs->mac1, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_BUT_NO_COOKIE; ++ ++ if (!check_cookie) ++ goto out; ++ ++ make_cookie(cookie, skb, checker); ++ ++ compute_mac2(computed_mac, data_start, data_len, cookie); ++ if (crypto_memneq(computed_mac, macs->mac2, COOKIE_LEN)) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE_BUT_RATELIMITED; ++ if (!ratelimiter_allow(&checker->ratelimiter, skb)) ++ goto out; ++ ++ ret = VALID_MAC_WITH_COOKIE; ++ ++out: ++ return ret; ++} ++ ++void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer) ++{ ++ struct message_macs *macs = (struct message_macs *)((u8 *)message + len - sizeof(struct message_macs)); ++ ++ down_read(&peer->device->static_identity.lock); ++ if (unlikely(!peer->device->static_identity.has_identity)) { ++ memset(macs, 0, sizeof(struct message_macs)); ++ up_read(&peer->device->static_identity.lock); ++ return; ++ } ++ compute_mac1(macs->mac1, message, len, peer->handshake.remote_static, peer->device->static_identity.has_psk ? peer->device->static_identity.preshared_key : NULL); ++ up_read(&peer->device->static_identity.lock); ++ ++ down_write(&peer->latest_cookie.lock); ++ memcpy(peer->latest_cookie.last_mac1_sent, macs->mac1, COOKIE_LEN); ++ peer->latest_cookie.have_sent_mac1 = true; ++ up_write(&peer->latest_cookie.lock); ++ ++ down_read(&peer->latest_cookie.lock); ++ if (peer->latest_cookie.is_valid && time_is_after_jiffies64(peer->latest_cookie.birthdate + COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY)) ++ compute_mac2(macs->mac2, message, len, peer->latest_cookie.cookie); ++ else ++ memset(macs->mac2, 0, COOKIE_LEN); ++ up_read(&peer->latest_cookie.lock); ++} ++ ++void cookie_message_create(struct message_handshake_cookie *dst, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker) ++{ ++ struct message_macs *macs = (struct message_macs *)((u8 *)data_start + data_len - sizeof(struct message_macs)); ++ u8 cookie[COOKIE_LEN]; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE); ++ dst->receiver_index = index; ++ get_random_bytes(dst->nonce, COOKIE_NONCE_LEN); ++ blake2s(dst->nonce, dst->nonce, NULL, COOKIE_NONCE_LEN, COOKIE_NONCE_LEN, 0); /* Avoid directly transmitting RNG output. */ ++ ++ make_cookie(cookie, skb, checker); ++ xchacha20poly1305_encrypt(dst->encrypted_cookie, cookie, COOKIE_LEN, macs->mac1, COOKIE_LEN, dst->nonce, checker->cookie_encryption_key); ++} ++ ++void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg) ++{ ++ u8 cookie[COOKIE_LEN]; ++ struct index_hashtable_entry *entry; ++ bool ret; ++ ++ entry = index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE | INDEX_HASHTABLE_KEYPAIR, src->receiver_index); ++ if (!unlikely(entry)) ++ return; ++ ++ down_read(&entry->peer->latest_cookie.lock); ++ if (unlikely(!entry->peer->latest_cookie.have_sent_mac1)) { ++ up_read(&entry->peer->latest_cookie.lock); ++ goto out; ++ } ++ ret = xchacha20poly1305_decrypt(cookie, src->encrypted_cookie, sizeof(src->encrypted_cookie), entry->peer->latest_cookie.last_mac1_sent, COOKIE_LEN, src->nonce, entry->peer->latest_cookie.cookie_decryption_key); ++ up_read(&entry->peer->latest_cookie.lock); ++ ++ if (ret) { ++ down_write(&entry->peer->latest_cookie.lock); ++ memcpy(entry->peer->latest_cookie.cookie, cookie, COOKIE_LEN); ++ entry->peer->latest_cookie.birthdate = get_jiffies_64(); ++ entry->peer->latest_cookie.is_valid = true; ++ entry->peer->latest_cookie.have_sent_mac1 = false; ++ up_write(&entry->peer->latest_cookie.lock); ++ } else ++ net_dbg_ratelimited("Could not decrypt invalid cookie response\n"); ++ ++out: ++ peer_put(entry->peer); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/data.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,493 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "noise.h" ++#include "device.h" ++#include "peer.h" ++#include "messages.h" ++#include "packets.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct encryption_skb_cb { ++ u8 ds; ++ u8 num_frags; ++ unsigned int plaintext_len, trailer_len; ++ struct sk_buff *trailer; ++ u64 nonce; ++}; ++ ++struct encryption_ctx { ++ struct padata_priv padata; ++ struct sk_buff_head queue; ++ packet_create_data_callback_t callback; ++ struct wireguard_peer *peer; ++ struct noise_keypair *keypair; ++}; ++ ++struct decryption_ctx { ++ struct padata_priv padata; ++ struct sk_buff *skb; ++ packet_consume_data_callback_t callback; ++ struct noise_keypair *keypair; ++ struct endpoint endpoint; ++ u64 nonce; ++ int ret; ++ u8 num_frags; ++}; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static struct kmem_cache *encryption_ctx_cache __read_mostly; ++static struct kmem_cache *decryption_ctx_cache __read_mostly; ++ ++int packet_init_data_caches(void) ++{ ++ BUILD_BUG_ON(sizeof(struct encryption_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); ++ encryption_ctx_cache = kmem_cache_create("wireguard_encryption_ctx", sizeof(struct encryption_ctx), 0, 0, NULL); ++ if (!encryption_ctx_cache) ++ return -ENOMEM; ++ decryption_ctx_cache = kmem_cache_create("wireguard_decryption_ctx", sizeof(struct decryption_ctx), 0, 0, NULL); ++ if (!decryption_ctx_cache) { ++ kmem_cache_destroy(encryption_ctx_cache); ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void packet_deinit_data_caches(void) ++{ ++ kmem_cache_destroy(encryption_ctx_cache); ++ kmem_cache_destroy(decryption_ctx_cache); ++} ++#endif ++ ++/* This is RFC6479, a replay detection bitmap algorithm that avoids bitshifts */ ++static inline bool counter_validate(union noise_counter *counter, u64 their_counter) ++{ ++ bool ret = false; ++ unsigned long index, index_current, top, i; ++ spin_lock_bh(&counter->receive.lock); ++ ++ if (unlikely(counter->receive.counter >= REJECT_AFTER_MESSAGES + 1 || their_counter >= REJECT_AFTER_MESSAGES)) ++ goto out; ++ ++ ++their_counter; ++ ++ if (unlikely((COUNTER_WINDOW_SIZE + their_counter) < counter->receive.counter)) ++ goto out; ++ ++ index = their_counter >> ilog2(COUNTER_REDUNDANT_BITS); ++ ++ if (likely(their_counter > counter->receive.counter)) { ++ index_current = counter->receive.counter >> ilog2(COUNTER_REDUNDANT_BITS); ++ top = min_t(unsigned long, index - index_current, COUNTER_BITS_TOTAL / BITS_PER_LONG); ++ for (i = 1; i <= top; ++i) ++ counter->receive.backtrack[(i + index_current) & ((COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1)] = 0; ++ counter->receive.counter = their_counter; ++ } ++ ++ index &= (COUNTER_BITS_TOTAL / BITS_PER_LONG) - 1; ++ ret = !test_and_set_bit(their_counter & (COUNTER_REDUNDANT_BITS - 1), &counter->receive.backtrack[index]); ++ ++out: ++ spin_unlock_bh(&counter->receive.lock); ++ return ret; ++} ++#include "selftest/counter.h" ++ ++static inline unsigned int skb_padding(struct sk_buff *skb) ++{ ++ /* We do this modulo business with the MTU, just in case the networking layer ++ * gives us a packet that's bigger than the MTU. Now that we support GSO, this ++ * shouldn't be a real problem, and this can likely be removed. But, caution! */ ++ unsigned int last_unit = skb->len % skb->dev->mtu; ++ unsigned int padded_size = (last_unit + MESSAGE_PADDING_MULTIPLE - 1) & ~(MESSAGE_PADDING_MULTIPLE - 1); ++ if (padded_size > skb->dev->mtu) ++ padded_size = skb->dev->mtu; ++ return padded_size - last_unit; ++} ++ ++static inline void skb_reset(struct sk_buff *skb) ++{ ++ skb_scrub_packet(skb, false); ++ memset(&skb->headers_start, 0, offsetof(struct sk_buff, headers_end) - offsetof(struct sk_buff, headers_start)); ++ skb->queue_mapping = 0; ++ skb->nohdr = 0; ++ skb->peeked = 0; ++ skb->mac_len = 0; ++ skb->dev = NULL; ++#ifdef CONFIG_NET_SCHED ++ skb->tc_index = 0; ++ skb_reset_tc(skb); ++#endif ++ skb->hdr_len = skb_headroom(skb); ++ skb_reset_mac_header(skb); ++ skb_reset_network_header(skb); ++ skb_probe_transport_header(skb, 0); ++} ++ ++static inline void skb_encrypt(struct sk_buff *skb, struct noise_keypair *keypair, bool have_simd) ++{ ++ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb; ++ struct scatterlist sg[cb->num_frags]; /* This should be bound to at most 128 by the caller. */ ++ struct message_data *header; ++ ++ /* We have to remember to add the checksum to the innerpacket, in case the receiver forwards it. */ ++ if (likely(!skb_checksum_setup(skb, true))) ++ skb_checksum_help(skb); ++ ++ /* Only after checksumming can we safely add on the padding at the end and the header. */ ++ header = (struct message_data *)skb_push(skb, sizeof(struct message_data)); ++ header->header.type = cpu_to_le32(MESSAGE_DATA); ++ header->key_idx = keypair->remote_index; ++ header->counter = cpu_to_le64(cb->nonce); ++ pskb_put(skb, cb->trailer, cb->trailer_len); ++ ++ /* Now we can encrypt the scattergather segments */ ++ sg_init_table(sg, cb->num_frags); ++ skb_to_sgvec(skb, sg, sizeof(struct message_data), noise_encrypted_len(cb->plaintext_len)); ++ chacha20poly1305_encrypt_sg(sg, sg, cb->plaintext_len, NULL, 0, cb->nonce, keypair->sending.key, have_simd); ++} ++ ++static inline bool skb_decrypt(struct sk_buff *skb, u8 num_frags, u64 nonce, struct noise_symmetric_key *key) ++{ ++ struct scatterlist sg[num_frags]; /* This should be bound to at most 128 by the caller. */ ++ ++ if (unlikely(!key)) ++ return false; ++ ++ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME) || key->counter.receive.counter >= REJECT_AFTER_MESSAGES)) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ sg_init_table(sg, num_frags); ++ skb_to_sgvec(skb, sg, 0, skb->len); ++ ++ if (!chacha20poly1305_decrypt_sg(sg, sg, skb->len, NULL, 0, nonce, key->key)) ++ return false; ++ ++ return pskb_trim(skb, skb->len - noise_encrypted_len(0)) == 0; ++} ++ ++static inline bool get_encryption_nonce(u64 *nonce, struct noise_symmetric_key *key) ++{ ++ if (unlikely(!key)) ++ return false; ++ ++ if (unlikely(!key->is_valid || time_is_before_eq_jiffies64(key->birthdate + REJECT_AFTER_TIME))) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ *nonce = atomic64_inc_return(&key->counter.counter) - 1; ++ if (*nonce >= REJECT_AFTER_MESSAGES) { ++ key->is_valid = false; ++ return false; ++ } ++ ++ return true; ++} ++ ++static inline void queue_encrypt_reset(struct sk_buff_head *queue, struct noise_keypair *keypair) ++{ ++ struct sk_buff *skb; ++ bool have_simd = chacha20poly1305_init_simd(); ++ skb_queue_walk(queue, skb) { ++ skb_encrypt(skb, keypair, have_simd); ++ skb_reset(skb); ++ } ++ chacha20poly1305_deinit_simd(have_simd); ++ noise_keypair_put(keypair); ++} ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static void do_encryption(struct padata_priv *padata) ++{ ++ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata); ++ ++ queue_encrypt_reset(&ctx->queue, ctx->keypair); ++ padata_do_serial(padata); ++} ++ ++static void finish_encryption(struct padata_priv *padata) ++{ ++ struct encryption_ctx *ctx = container_of(padata, struct encryption_ctx, padata); ++ ++ ctx->callback(&ctx->queue, ctx->peer); ++ atomic_dec(&ctx->peer->parallel_encryption_inflight); ++ peer_put(ctx->peer); ++ kmem_cache_free(encryption_ctx_cache, ctx); ++} ++ ++static inline int start_encryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu) ++{ ++ memset(priv, 0, sizeof(struct padata_priv)); ++ priv->parallel = do_encryption; ++ priv->serial = finish_encryption; ++ return padata_do_parallel(padata, priv, cb_cpu); ++} ++ ++static inline unsigned int choose_cpu(__le32 key) ++{ ++ unsigned int cpu_index, cpu, cb_cpu; ++ ++ /* This ensures that packets encrypted to the same key are sent in-order. */ ++ cpu_index = ((__force unsigned int)key) % cpumask_weight(cpu_online_mask); ++ cb_cpu = cpumask_first(cpu_online_mask); ++ for (cpu = 0; cpu < cpu_index; ++cpu) ++ cb_cpu = cpumask_next(cb_cpu, cpu_online_mask); ++ ++ return cb_cpu; ++} ++#endif ++ ++int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback) ++{ ++ int ret = -ENOKEY; ++ struct noise_keypair *keypair; ++ struct sk_buff *skb; ++ ++ rcu_read_lock(); ++ keypair = noise_keypair_get(rcu_dereference(peer->keypairs.current_keypair)); ++ if (unlikely(!keypair)) ++ goto err_rcu; ++ rcu_read_unlock(); ++ ++ skb_queue_walk(queue, skb) { ++ struct encryption_skb_cb *cb = (struct encryption_skb_cb *)skb->cb; ++ unsigned int padding_len, num_frags; ++ ++ if (unlikely(!get_encryption_nonce(&cb->nonce, &keypair->sending))) ++ goto err; ++ ++ padding_len = skb_padding(skb); ++ cb->trailer_len = padding_len + noise_encrypted_len(0); ++ cb->plaintext_len = skb->len + padding_len; ++ ++ /* Store the ds bit in the cb */ ++ cb->ds = ip_tunnel_ecn_encap(0 /* No outer TOS: no leak. TODO: should we use flowi->tos as outer? */, ip_hdr(skb), skb); ++ ++ /* Expand data section to have room for padding and auth tag */ ++ ret = skb_cow_data(skb, cb->trailer_len, &cb->trailer); ++ if (unlikely(ret < 0)) ++ goto err; ++ num_frags = ret; ++ ret = -ENOMEM; ++ if (unlikely(num_frags > 128)) ++ goto err; ++ cb->num_frags = num_frags; ++ ++ /* Set the padding to zeros, and make sure it and the auth tag are part of the skb */ ++ memset(skb_tail_pointer(cb->trailer), 0, padding_len); ++ ++ /* Expand head section to have room for our header and the network stack's headers. */ ++ ret = skb_cow_head(skb, DATA_PACKET_HEAD_ROOM); ++ if (unlikely(ret < 0)) ++ goto err; ++ ++ /* After the first time through the loop, if we've suceeded with a legitimate nonce, ++ * then we don't want a -ENOKEY error if subsequent nonces fail. Rather, if this ++ * condition arises, we simply want error out hard, and drop the entire queue. This ++ * is partially lazy programming and TODO: this could be made to only requeue the ++ * ones that had no nonce. But I'm not sure it's worth the added complexity, given ++ * how rarely that condition should arise. */ ++ ret = -EPIPE; ++ } ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ if ((skb_queue_len(queue) > 1 || queue->next->len > 256 || atomic_read(&peer->parallel_encryption_inflight) > 0) && cpumask_weight(cpu_online_mask) > 1) { ++ unsigned int cpu = choose_cpu(keypair->remote_index); ++ struct encryption_ctx *ctx = kmem_cache_alloc(encryption_ctx_cache, GFP_ATOMIC); ++ if (!ctx) ++ goto serial_encrypt; ++ skb_queue_head_init(&ctx->queue); ++ skb_queue_splice_init(queue, &ctx->queue); ++ ctx->callback = callback; ++ ctx->keypair = keypair; ++ ctx->peer = peer_rcu_get(peer); ++ ret = -EBUSY; ++ if (unlikely(!ctx->peer)) ++ goto err_parallel; ++ atomic_inc(&peer->parallel_encryption_inflight); ++ ret = start_encryption(peer->device->parallel_send, &ctx->padata, cpu); ++ if (unlikely(ret < 0)) { ++ atomic_dec(&peer->parallel_encryption_inflight); ++ peer_put(ctx->peer); ++err_parallel: ++ skb_queue_splice(&ctx->queue, queue); ++ kmem_cache_free(encryption_ctx_cache, ctx); ++ goto err; ++ } ++ } else ++serial_encrypt: ++#endif ++ { ++ queue_encrypt_reset(queue, keypair); ++ callback(queue, peer); ++ } ++ return 0; ++ ++err: ++ noise_keypair_put(keypair); ++ return ret; ++err_rcu: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static void begin_decrypt_packet(struct decryption_ctx *ctx) ++{ ++ if (unlikely(!skb_decrypt(ctx->skb, ctx->num_frags, ctx->nonce, &ctx->keypair->receiving))) ++ goto err; ++ ++ skb_reset(ctx->skb); ++ ctx->ret = 0; ++ return; ++ ++err: ++ ctx->ret = -ENOKEY; ++ peer_put(ctx->keypair->entry.peer); ++} ++ ++static void finish_decrypt_packet(struct decryption_ctx *ctx) ++{ ++ struct noise_keypairs *keypairs; ++ bool used_new_key = false; ++ int ret = ctx->ret; ++ if (ret) ++ goto err; ++ ++ keypairs = &ctx->keypair->entry.peer->keypairs; ++ ret = counter_validate(&ctx->keypair->receiving.counter, ctx->nonce) ? 0 : -ERANGE; ++ ++ if (likely(!ret)) ++ used_new_key = noise_received_with_keypair(&ctx->keypair->entry.peer->keypairs, ctx->keypair); ++ else { ++ net_dbg_ratelimited("Packet has invalid nonce %Lu (max %Lu)\n", ctx->nonce, ctx->keypair->receiving.counter.receive.counter); ++ peer_put(ctx->keypair->entry.peer); ++ goto err; ++ } ++ ++ noise_keypair_put(ctx->keypair); ++ ctx->callback(ctx->skb, ctx->keypair->entry.peer, &ctx->endpoint, used_new_key, 0); ++ return; ++ ++err: ++ noise_keypair_put(ctx->keypair); ++ ctx->callback(ctx->skb, NULL, NULL, false, ret); ++} ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++static void do_decryption(struct padata_priv *padata) ++{ ++ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata); ++ begin_decrypt_packet(ctx); ++ padata_do_serial(padata); ++} ++ ++static void finish_decryption(struct padata_priv *padata) ++{ ++ struct decryption_ctx *ctx = container_of(padata, struct decryption_ctx, padata); ++ finish_decrypt_packet(ctx); ++ kmem_cache_free(decryption_ctx_cache, ctx); ++} ++ ++static inline int start_decryption(struct padata_instance *padata, struct padata_priv *priv, int cb_cpu) ++{ ++ priv->parallel = do_decryption; ++ priv->serial = finish_decryption; ++ return padata_do_parallel(padata, priv, cb_cpu); ++} ++#endif ++ ++void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback) ++{ ++ int ret; ++ struct endpoint endpoint; ++ unsigned int num_frags; ++ struct sk_buff *trailer; ++ struct message_data *header; ++ struct noise_keypair *keypair; ++ u64 nonce; ++ __le32 idx; ++ ++ ret = socket_endpoint_from_skb(&endpoint, skb); ++ if (unlikely(ret < 0)) ++ goto err; ++ ++ ret = -ENOMEM; ++ if (unlikely(!pskb_may_pull(skb, offset + sizeof(struct message_data)))) ++ goto err; ++ ++ header = (struct message_data *)(skb->data + offset); ++ offset += sizeof(struct message_data); ++ skb_pull(skb, offset); ++ ++ idx = header->key_idx; ++ nonce = le64_to_cpu(header->counter); ++ ++ ret = skb_cow_data(skb, 0, &trailer); ++ if (unlikely(ret < 0)) ++ goto err; ++ num_frags = ret; ++ ret = -ENOMEM; ++ if (unlikely(num_frags > 128)) ++ goto err; ++ ret = -EINVAL; ++ rcu_read_lock(); ++ keypair = noise_keypair_get((struct noise_keypair *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_KEYPAIR, idx)); ++ rcu_read_unlock(); ++ if (unlikely(!keypair)) ++ goto err; ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ if (cpumask_weight(cpu_online_mask) > 1) { ++ unsigned int cpu = choose_cpu(idx); ++ struct decryption_ctx *ctx; ++ ++ ret = -ENOMEM; ++ ctx = kmem_cache_alloc(decryption_ctx_cache, GFP_ATOMIC); ++ if (unlikely(!ctx)) ++ goto err_peer; ++ ++ ctx->skb = skb; ++ ctx->keypair = keypair; ++ ctx->callback = callback; ++ ctx->nonce = nonce; ++ ctx->num_frags = num_frags; ++ ctx->endpoint = endpoint; ++ ret = start_decryption(wg->parallel_receive, &ctx->padata, cpu); ++ if (unlikely(ret)) { ++ kmem_cache_free(decryption_ctx_cache, ctx); ++ goto err_peer; ++ } ++ } else ++#endif ++ { ++ struct decryption_ctx ctx = { ++ .skb = skb, ++ .keypair = keypair, ++ .callback = callback, ++ .nonce = nonce, ++ .num_frags = num_frags, ++ .endpoint = endpoint ++ }; ++ begin_decrypt_packet(&ctx); ++ finish_decrypt_packet(&ctx); ++ } ++ return; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++err_peer: ++ peer_put(keypair->entry.peer); ++ noise_keypair_put(keypair); ++#endif ++err: ++ callback(skb, NULL, NULL, false, ret); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/device.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,387 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "socket.h" ++#include "timers.h" ++#include "device.h" ++#include "config.h" ++#include "peer.h" ++#include "uapi.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++#include ++#include ++#endif ++ ++static int open_peer(struct wireguard_peer *peer, void *data) ++{ ++ timers_init_peer(peer); ++ packet_send_queue(peer); ++ if (peer->persistent_keepalive_interval) ++ packet_send_keepalive(peer); ++ return 0; ++} ++ ++static int open(struct net_device *dev) ++{ ++ int ret; ++ struct wireguard_device *wg = netdev_priv(dev); ++ struct inet6_dev *dev_v6 = __in6_dev_get(dev); ++ struct in_device *dev_v4 = __in_dev_get_rtnl(dev); ++ ++ if (dev_v4) { ++ /* TODO: when we merge to mainline, put this check near the ip_rt_send_redirect ++ * call of ip_forward in net/ipv4/ip_forward.c, similar to the current secpath ++ * check, rather than turning it off like this. This is just a stop gap solution ++ * while we're an out of tree module. */ ++ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); ++ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false; ++ } ++ if (dev_v6) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++ dev_v6->addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; ++#else ++ dev_v6->cnf.addr_gen_mode = IN6_ADDR_GEN_MODE_NONE; ++#endif ++ ++ ret = socket_init(wg); ++ if (ret < 0) ++ return ret; ++ peer_for_each(wg, open_peer, NULL); ++ return 0; ++} ++ ++static int clear_noise_peer(struct wireguard_peer *peer, void *data) ++{ ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ if (peer->timers_enabled) ++ del_timer(&peer->timer_kill_ephemerals); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int suspending_clear_noise_peers(struct notifier_block *nb, unsigned long action, void *data) ++{ ++ struct wireguard_device *wg = container_of(nb, struct wireguard_device, clear_peers_on_suspend); ++ if (action == PM_HIBERNATION_PREPARE || action == PM_SUSPEND_PREPARE) { ++ peer_for_each(wg, clear_noise_peer, NULL); ++ rcu_barrier(); ++ } ++ return 0; ++} ++#endif ++ ++static int stop_peer(struct wireguard_peer *peer, void *data) ++{ ++ timers_uninit_peer(peer); ++ clear_noise_peer(peer, data); ++ return 0; ++} ++ ++static int stop(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ peer_for_each(wg, stop_peer, NULL); ++ skb_queue_purge(&wg->incoming_handshakes); ++ socket_uninit(wg); ++ return 0; ++} ++ ++static void skb_unsendable(struct sk_buff *skb, struct net_device *dev) ++{ ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ /* This conntrack stuff is because the rate limiting needs to be applied ++ * to the original src IP, so we have to restore saddr in the IP header. ++ * It's not needed if conntracking isn't in the kernel, because in that ++ * case the saddr wouldn't be NAT-transformed anyway. */ ++ enum ip_conntrack_info ctinfo; ++ struct nf_conn *ct = nf_ct_get(skb, &ctinfo); ++#endif ++ ++dev->stats.tx_errors; ++ ++ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) { ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ if (ct) ++ ip_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.ip; ++#endif ++ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); ++ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) { ++#if IS_ENABLED(CONFIG_NF_CONNTRACK) ++ if (ct) ++ ipv6_hdr(skb)->saddr = ct->tuplehash[0].tuple.src.u3.in6; ++#endif ++ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); ++ } ++ kfree_skb(skb); ++} ++ ++static netdev_tx_t xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ struct wireguard_peer *peer; ++ int ret; ++ ++ if (unlikely(dev_recursion_level() > 4)) { ++ ret = -ELOOP; ++ net_dbg_ratelimited("Routing loop detected\n"); ++ skb_unsendable(skb, dev); ++ goto err; ++ } ++ ++ peer = routing_table_lookup_dst(&wg->peer_routing_table, skb); ++ if (unlikely(!peer)) { ++ ret = -ENOKEY; ++ net_dbg_skb_ratelimited("No peer is configured for %pISc\n", skb); ++ goto err; ++ } ++ ++ read_lock_bh(&peer->endpoint_lock); ++ ret = peer->endpoint.addr.sa_family != AF_INET && peer->endpoint.addr.sa_family != AF_INET6; ++ read_unlock_bh(&peer->endpoint_lock); ++ if (unlikely(ret)) { ++ ret = -EHOSTUNREACH; ++ net_dbg_ratelimited("No valid endpoint has been configured or discovered for peer %Lu\n", peer->internal_id); ++ goto err_peer; ++ } ++ ++ /* If the queue is getting too big, we start removing the oldest packets until it's small again. ++ * We do this before adding the new packet, so we don't remove GSO segments that are in excess. */ ++ while (skb_queue_len(&peer->tx_packet_queue) > MAX_QUEUED_OUTGOING_PACKETS) ++ dev_kfree_skb(skb_dequeue(&peer->tx_packet_queue)); ++ ++ if (!skb_is_gso(skb)) ++ skb->next = NULL; ++ else { ++ struct sk_buff *segs = skb_gso_segment(skb, 0); ++ if (unlikely(IS_ERR(segs))) { ++ ret = PTR_ERR(segs); ++ goto err_peer; ++ } ++ dev_kfree_skb(skb); ++ skb = segs; ++ } ++ while (skb) { ++ struct sk_buff *next = skb->next; ++ skb->next = skb->prev = NULL; ++ ++ skb = skb_share_check(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ continue; ++ ++ /* We only need to keep the original dst around for icmp, ++ * so at this point we're in a position to drop it. */ ++ skb_dst_drop(skb); ++ ++ skb_queue_tail(&peer->tx_packet_queue, skb); ++ skb = next; ++ } ++ ++ packet_send_queue(peer); ++ peer_put(peer); ++ return NETDEV_TX_OK; ++ ++err_peer: ++ peer_put(peer); ++err: ++ skb_unsendable(skb, dev); ++ return ret; ++} ++ ++ ++static int ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) ++ return -EPERM; ++ ++ switch (cmd) { ++ case WG_GET_DEVICE: ++ return config_get_device(wg, ifr->ifr_ifru.ifru_data); ++ case WG_SET_DEVICE: ++ return config_set_device(wg, ifr->ifr_ifru.ifru_data); ++ } ++ return -EINVAL; ++} ++ ++static const struct net_device_ops netdev_ops = { ++ .ndo_open = open, ++ .ndo_stop = stop, ++ .ndo_start_xmit = xmit, ++ .ndo_get_stats64 = ip_tunnel_get_stats64, ++ .ndo_do_ioctl = ioctl ++}; ++ ++static void destruct(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ mutex_lock(&wg->device_update_lock); ++ peer_remove_all(wg); ++ wg->incoming_port = 0; ++ destroy_workqueue(wg->workqueue); ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ padata_free(wg->parallel_send); ++ padata_free(wg->parallel_receive); ++ destroy_workqueue(wg->parallelqueue); ++#endif ++ routing_table_free(&wg->peer_routing_table); ++ memzero_explicit(&wg->static_identity, sizeof(struct noise_static_identity)); ++ skb_queue_purge(&wg->incoming_handshakes); ++ socket_uninit(wg); ++ cookie_checker_uninit(&wg->cookie_checker); ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&wg->clear_peers_on_suspend); ++#endif ++ mutex_unlock(&wg->device_update_lock); ++ free_percpu(dev->tstats); ++ ++ put_net(wg->creating_net); ++ ++ pr_debug("Device %s has been deleted\n", dev->name); ++ free_netdev(dev); ++} ++ ++static void setup(struct net_device *dev) ++{ ++ struct wireguard_device *wg = netdev_priv(dev); ++ enum { WG_NETDEV_FEATURES = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA }; ++ ++ dev->netdev_ops = &netdev_ops; ++ dev->destructor = destruct; ++ dev->hard_header_len = 0; ++ dev->addr_len = 0; ++ dev->needed_headroom = DATA_PACKET_HEAD_ROOM; ++ dev->needed_tailroom = noise_encrypted_len(MESSAGE_PADDING_MULTIPLE); ++ dev->type = ARPHRD_NONE; ++ dev->flags = IFF_POINTOPOINT | IFF_NOARP; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) ++ dev->flags |= IFF_NO_QUEUE; ++#else ++ dev->tx_queue_len = 0; ++#endif ++ dev->features |= NETIF_F_LLTX; ++ dev->features |= WG_NETDEV_FEATURES; ++ dev->hw_features |= WG_NETDEV_FEATURES; ++ dev->hw_enc_features |= WG_NETDEV_FEATURES; ++ dev->mtu = ETH_DATA_LEN - MESSAGE_MINIMUM_LENGTH - sizeof(struct udphdr) - max(sizeof(struct ipv6hdr), sizeof(struct iphdr)); ++ ++ /* We need to keep the dst around in case of icmp replies. */ ++ netif_keep_dst(dev); ++ ++ memset(wg, 0, sizeof(struct wireguard_device)); ++} ++ ++static int newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) ++{ ++ int ret = -ENOMEM; ++ struct wireguard_device *wg = netdev_priv(dev); ++ ++ wg->creating_net = get_net(src_net); ++ init_rwsem(&wg->static_identity.lock); ++ mutex_init(&wg->socket_update_lock); ++ mutex_init(&wg->device_update_lock); ++ skb_queue_head_init(&wg->incoming_handshakes); ++ INIT_WORK(&wg->incoming_handshakes_work, packet_process_queued_handshake_packets); ++ pubkey_hashtable_init(&wg->peer_hashtable); ++ index_hashtable_init(&wg->index_hashtable); ++ routing_table_init(&wg->peer_routing_table); ++ INIT_LIST_HEAD(&wg->peer_list); ++ ++ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); ++ if (!dev->tstats) ++ goto error_1; ++ ++ wg->workqueue = alloc_workqueue("wg-%s", WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name); ++ if (!wg->workqueue) ++ goto error_2; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ wg->parallelqueue = alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1, dev->name); ++ if (!wg->parallelqueue) ++ goto error_3; ++ ++ wg->parallel_send = padata_alloc_possible(wg->parallelqueue); ++ if (!wg->parallel_send) ++ goto error_4; ++ padata_start(wg->parallel_send); ++ ++ wg->parallel_receive = padata_alloc_possible(wg->parallelqueue); ++ if (!wg->parallel_receive) ++ goto error_5; ++ padata_start(wg->parallel_receive); ++#endif ++ ++ ret = cookie_checker_init(&wg->cookie_checker, wg); ++ if (ret < 0) ++ goto error_6; ++ ++#ifdef CONFIG_PM_SLEEP ++ wg->clear_peers_on_suspend.notifier_call = suspending_clear_noise_peers; ++ ret = register_pm_notifier(&wg->clear_peers_on_suspend); ++ if (ret < 0) ++ goto error_7; ++#endif ++ ++ ret = register_netdevice(dev); ++ if (ret < 0) ++ goto error_8; ++ ++ pr_debug("Device %s has been created\n", dev->name); ++ ++ return 0; ++ ++error_8: ++#ifdef CONFIG_PM_SLEEP ++ unregister_pm_notifier(&wg->clear_peers_on_suspend); ++error_7: ++#endif ++ cookie_checker_uninit(&wg->cookie_checker); ++error_6: ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ padata_free(wg->parallel_receive); ++error_5: ++ padata_free(wg->parallel_send); ++error_4: ++ destroy_workqueue(wg->parallelqueue); ++error_3: ++#endif ++ destroy_workqueue(wg->workqueue); ++error_2: ++ free_percpu(dev->tstats); ++error_1: ++ put_net(src_net); ++ return ret; ++} ++ ++static struct rtnl_link_ops link_ops __read_mostly = { ++ .kind = KBUILD_MODNAME, ++ .priv_size = sizeof(struct wireguard_device), ++ .setup = setup, ++ .newlink = newlink, ++}; ++ ++int device_init(void) ++{ ++ return rtnl_link_register(&link_ops); ++} ++ ++void device_uninit(void) ++{ ++ rtnl_link_unregister(&link_ops); ++ rcu_barrier(); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/hashtables.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,136 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "hashtables.h" ++#include "peer.h" ++#include "noise.h" ++ ++static inline struct hlist_head *pubkey_bucket(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ /* siphash gives us a secure 64bit number based on a random key. Since the bits are ++ * uniformly distributed, we can then mask off to get the bits we need. */ ++ return &table->hashtable[siphash(pubkey, NOISE_PUBLIC_KEY_LEN, &table->key) & (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++void pubkey_hashtable_init(struct pubkey_hashtable *table) ++{ ++ get_random_bytes(&table->key, sizeof(table->key)); ++ hash_init(table->hashtable); ++ mutex_init(&table->lock); ++} ++ ++void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_add_head_rcu(&peer->pubkey_hash, pubkey_bucket(table, peer->handshake.remote_static)); ++ mutex_unlock(&table->lock); ++} ++ ++void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer) ++{ ++ mutex_lock(&table->lock); ++ hlist_del_init_rcu(&peer->pubkey_hash); ++ mutex_unlock(&table->lock); ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]) ++{ ++ struct wireguard_peer *iter_peer, *peer = NULL; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(iter_peer, pubkey_bucket(table, pubkey), pubkey_hash) { ++ if (!memcmp(pubkey, iter_peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN)) { ++ peer = iter_peer; ++ break; ++ } ++ } ++ peer = peer_get(peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++static inline struct hlist_head *index_bucket(struct index_hashtable *table, const __le32 index) ++{ ++ /* Since the indices are random and thus all bits are uniformly distributed, ++ * we can find its bucket simply by masking. */ ++ return &table->hashtable[(__force u32)index & (HASH_SIZE(table->hashtable) - 1)]; ++} ++ ++void index_hashtable_init(struct index_hashtable *table) ++{ ++ get_random_bytes(&table->key, sizeof(table->key)); ++ hash_init(table->hashtable); ++ spin_lock_init(&table->lock); ++} ++ ++__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry) ++{ ++ struct index_hashtable_entry *existing_entry; ++ u32 counter = get_random_int(); ++ ++ spin_lock(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock(&table->lock); ++ ++ rcu_read_lock(); ++ ++search_unused_slot: ++ /* First we try to find an unused slot, randomly, while unlocked. */ ++ entry->index = (__force __le32)siphash_2u32(get_random_int(), counter++, &table->key); ++ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) { ++ if (existing_entry->index == entry->index) ++ goto search_unused_slot; /* If it's already in use, we continue searching. */ ++ } ++ ++ /* Once we've found an unused slot, we lock it, and then double-check ++ * that nobody else stole it from us. */ ++ spin_lock(&table->lock); ++ hlist_for_each_entry_rcu(existing_entry, index_bucket(table, entry->index), index_hash) { ++ if (existing_entry->index == entry->index) { ++ spin_unlock(&table->lock); ++ goto search_unused_slot; /* If it was stolen, we start over. */ ++ } ++ } ++ /* Otherwise, we know we have it exclusively (since we're locked), so we insert. */ ++ hlist_add_head_rcu(&entry->index_hash, index_bucket(table, entry->index)); ++ spin_unlock(&table->lock); ++ ++ rcu_read_unlock(); ++ ++ return entry->index; ++} ++ ++void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new) ++{ ++ spin_lock(&table->lock); ++ new->index = old->index; ++ hlist_replace_rcu(&old->index_hash, &new->index_hash); ++ INIT_HLIST_NODE(&old->index_hash); ++ spin_unlock(&table->lock); ++} ++ ++void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry) ++{ ++ spin_lock(&table->lock); ++ hlist_del_init_rcu(&entry->index_hash); ++ spin_unlock(&table->lock); ++} ++ ++/* Returns a strong reference to a entry->peer */ ++struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index) ++{ ++ struct index_hashtable_entry *iter_entry, *entry = NULL; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(iter_entry, index_bucket(table, index), index_hash) { ++ if (iter_entry->index == index && (iter_entry->type & type_mask)) { ++ entry = iter_entry; ++ break; ++ } ++ } ++ if (likely(entry)) { ++ entry->peer = peer_get(entry->peer); ++ if (unlikely(!entry->peer)) ++ entry = NULL; ++ } ++ rcu_read_unlock(); ++ return entry; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/main.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,70 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "version.h" ++#include "device.h" ++#include "noise.h" ++#include "packets.h" ++#include "crypto/chacha20poly1305.h" ++#include "crypto/blake2s.h" ++#include "crypto/curve25519.h" ++ ++#include ++#include ++#include ++#include ++ ++static int __init mod_init(void) ++{ ++ int ret; ++ ++#ifdef DEBUG ++ if (!routing_table_selftest() || !packet_counter_selftest() || !curve25519_selftest() || !chacha20poly1305_selftest() || !blake2s_selftest()) ++ return -ENOTRECOVERABLE; ++#endif ++ chacha20poly1305_init(); ++ noise_init(); ++ ++ ret = ratelimiter_module_init(); ++ if (ret < 0) ++ return ret; ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ ret = packet_init_data_caches(); ++ if (ret < 0) ++ goto err_packet; ++#endif ++ ++ ret = device_init(); ++ if (ret < 0) ++ goto err_device; ++ ++ pr_info("WireGuard " WIREGUARD_VERSION " loaded. See www.wireguard.io for information.\n"); ++ pr_info("Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved.\n"); ++ ++ return 0; ++ ++err_device: ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ packet_deinit_data_caches(); ++err_packet: ++#endif ++ ratelimiter_module_deinit(); ++ return ret; ++} ++ ++static void __exit mod_exit(void) ++{ ++ device_uninit(); ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ packet_deinit_data_caches(); ++#endif ++ ratelimiter_module_deinit(); ++ pr_debug("WireGuard has been unloaded\n"); ++} ++ ++module_init(mod_init); ++module_exit(mod_exit); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Fast, secure, and modern VPN tunnel"); ++MODULE_AUTHOR("Jason A. Donenfeld "); ++MODULE_ALIAS_RTNL_LINK(KBUILD_MODNAME); +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/noise.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,593 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "noise.h" ++#include "device.h" ++#include "peer.h" ++#include "messages.h" ++#include "packets.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* This implements Noise_IK: ++ * ++ * <- s ++ * ****** ++ * -> e, es, s, ss, t ++ * <- e, ee, se ++ */ ++ ++static const u8 handshake_name[33] = "Noise_IK_25519_ChaChaPoly_BLAKE2s"; ++static const u8 handshake_psk_name[36] = "NoisePSK_IK_25519_ChaChaPoly_BLAKE2s"; ++static u8 handshake_name_hash[NOISE_HASH_LEN] __read_mostly; ++static u8 handshake_psk_name_hash[NOISE_HASH_LEN] __read_mostly; ++static const u8 identifier_name[34] = "WireGuard v0 zx2c4 Jason@zx2c4.com"; ++static atomic64_t keypair_counter = ATOMIC64_INIT(0); ++ ++void noise_init(void) ++{ ++ blake2s(handshake_name_hash, handshake_name, NULL, NOISE_HASH_LEN, sizeof(handshake_name), 0); ++ blake2s(handshake_psk_name_hash, handshake_psk_name, NULL, NOISE_HASH_LEN, sizeof(handshake_psk_name), 0); ++} ++ ++void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer) ++{ ++ memset(handshake, 0, sizeof(struct noise_handshake)); ++ init_rwsem(&handshake->lock); ++ handshake->entry.type = INDEX_HASHTABLE_HANDSHAKE; ++ handshake->entry.peer = peer; ++ memcpy(handshake->remote_static, peer_public_key, NOISE_PUBLIC_KEY_LEN); ++ handshake->static_identity = static_identity; ++ handshake->state = HANDSHAKE_ZEROED; ++} ++ ++void noise_handshake_clear(struct noise_handshake *handshake) ++{ ++ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ down_write(&handshake->lock); ++ memset(&handshake->ephemeral_public, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->ephemeral_private, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->remote_ephemeral, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(&handshake->hash, 0, NOISE_HASH_LEN); ++ memset(&handshake->chaining_key, 0, NOISE_HASH_LEN); ++ memset(&handshake->key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ handshake->remote_index = 0; ++ handshake->state = HANDSHAKE_ZEROED; ++ up_write(&handshake->lock); ++ index_hashtable_remove(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++} ++ ++static struct noise_keypair *keypair_create(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair = kzalloc(sizeof(struct noise_keypair), GFP_KERNEL); ++ if (unlikely(!keypair)) ++ return NULL; ++ keypair->internal_id = atomic64_inc_return(&keypair_counter); ++ keypair->entry.type = INDEX_HASHTABLE_KEYPAIR; ++ keypair->entry.peer = peer; ++ kref_init(&keypair->refcount); ++ return keypair; ++} ++ ++static void keypair_free_rcu(struct rcu_head *rcu) ++{ ++ struct noise_keypair *keypair = container_of(rcu, struct noise_keypair, rcu); ++ net_dbg_ratelimited("Keypair %Lu destroyed for peer %Lu\n", keypair->internal_id, keypair->entry.peer->internal_id); ++ kzfree(keypair); ++} ++ ++static void keypair_free_kref(struct kref *kref) ++{ ++ struct noise_keypair *keypair = container_of(kref, struct noise_keypair, refcount); ++ index_hashtable_remove(&keypair->entry.peer->device->index_hashtable, &keypair->entry); ++ call_rcu(&keypair->rcu, keypair_free_rcu); ++} ++ ++void noise_keypair_put(struct noise_keypair *keypair) ++{ ++ if (unlikely(!keypair)) ++ return; ++ kref_put(&keypair->refcount, keypair_free_kref); ++} ++ ++struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling noise_keypair_get without holding the RCU read lock."); ++ if (unlikely(!keypair || !kref_get_unless_zero(&keypair->refcount))) ++ return NULL; ++ return keypair; ++} ++ ++void noise_keypairs_clear(struct noise_keypairs *keypairs) ++{ ++ struct noise_keypair *old; ++ mutex_lock(&keypairs->keypair_update_lock); ++ old = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->previous_keypair, NULL); ++ noise_keypair_put(old); ++ old = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ noise_keypair_put(old); ++ old = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ rcu_assign_pointer(keypairs->current_keypair, NULL); ++ noise_keypair_put(old); ++ mutex_unlock(&keypairs->keypair_update_lock); ++} ++ ++static void add_new_keypair(struct noise_keypairs *keypairs, struct noise_keypair *new_keypair) ++{ ++ struct noise_keypair *previous_keypair, *next_keypair, *current_keypair; ++ ++ mutex_lock(&keypairs->keypair_update_lock); ++ previous_keypair = rcu_dereference_protected(keypairs->previous_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ next_keypair = rcu_dereference_protected(keypairs->next_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ current_keypair = rcu_dereference_protected(keypairs->current_keypair, lockdep_is_held(&keypairs->keypair_update_lock)); ++ if (new_keypair->i_am_the_initiator) { ++ /* If we're the initiator, it means we've sent a handshake, and received ++ * a confirmation response, which means this new keypair can now be used. */ ++ if (next_keypair) { ++ /* If there already was a next keypair pending, we demote it to be ++ * the previous keypair, and free the existing current. ++ * TODO: note that this means KCI can result in this transition. It ++ * would perhaps be more sound to always just get rid of the unused ++ * next keypair instead of putting it in the previous slot, but this ++ * might be a bit less robust. Something to think about and decide on. */ ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ rcu_assign_pointer(keypairs->previous_keypair, next_keypair); ++ noise_keypair_put(current_keypair); ++ } else /* If there wasn't an existing next keypair, we replace the ++ * previous with the current one. */ ++ rcu_assign_pointer(keypairs->previous_keypair, current_keypair); ++ /* At this point we can get rid of the old previous keypair, and set up ++ * the new keypair. */ ++ noise_keypair_put(previous_keypair); ++ rcu_assign_pointer(keypairs->current_keypair, new_keypair); ++ } else { ++ /* If we're the responder, it means we can't use the new keypair until ++ * we receive confirmation via the first data packet, so we get rid of ++ * the existing previous one, the possibly existing next one, and slide ++ * in the new next one. */ ++ rcu_assign_pointer(keypairs->next_keypair, new_keypair); ++ noise_keypair_put(next_keypair); ++ rcu_assign_pointer(keypairs->previous_keypair, NULL); ++ noise_keypair_put(previous_keypair); ++ } ++ mutex_unlock(&keypairs->keypair_update_lock); ++} ++ ++bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair) ++{ ++ bool ret = false; ++ struct noise_keypair *old_keypair; ++ ++ /* TODO: probably this needs the actual mutex, but we're in atomic context, ++ * so we can't take it here. Instead we just rely on RCU for the lookups. */ ++ rcu_read_lock(); ++ if (unlikely(received_keypair == rcu_dereference(keypairs->next_keypair))) { ++ ret = true; ++ /* When we've finally received the confirmation, we slide the next ++ * into the current, the current into the previous, and get rid of ++ * the old previous. */ ++ old_keypair = rcu_dereference(keypairs->previous_keypair); ++ rcu_assign_pointer(keypairs->previous_keypair, rcu_dereference(keypairs->current_keypair)); ++ noise_keypair_put(old_keypair); ++ rcu_assign_pointer(keypairs->current_keypair, received_keypair); ++ rcu_assign_pointer(keypairs->next_keypair, NULL); ++ } ++ rcu_read_unlock(); ++ ++ return ret; ++} ++ ++void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN]) ++{ ++ down_write(&static_identity->lock); ++ if (private_key) { ++ memcpy(static_identity->static_private, private_key, NOISE_PUBLIC_KEY_LEN); ++ curve25519_generate_public(static_identity->static_public, private_key); ++ static_identity->has_identity = true; ++ } else { ++ memset(static_identity->static_private, 0, NOISE_PUBLIC_KEY_LEN); ++ memset(static_identity->static_public, 0, NOISE_PUBLIC_KEY_LEN); ++ static_identity->has_identity = false; ++ } ++ up_write(&static_identity->lock); ++} ++ ++void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ down_write(&static_identity->lock); ++ if (preshared_key) { ++ memcpy(static_identity->preshared_key, preshared_key, NOISE_SYMMETRIC_KEY_LEN); ++ static_identity->has_psk = true; ++ } else { ++ memset(static_identity->preshared_key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ static_identity->has_psk = false; ++ } ++ up_write(&static_identity->lock); ++} ++ ++/* This is Hugo Krawczyk's HKDF: ++ * - https://eprint.iacr.org/2010/264.pdf ++ * - https://tools.ietf.org/html/rfc5869 ++ */ ++static void kdf(u8 *first_dst, u8 *second_dst, const u8 *data, ++ size_t first_len, size_t second_len, size_t data_len, ++ const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ u8 secret[BLAKE2S_OUTBYTES]; ++ u8 output[BLAKE2S_OUTBYTES + 1]; ++ BUG_ON(first_len > BLAKE2S_OUTBYTES || second_len > BLAKE2S_OUTBYTES); ++ ++ /* Extract entropy from data into secret */ ++ blake2s_hmac(secret, data, chaining_key, BLAKE2S_OUTBYTES, data_len, NOISE_HASH_LEN); ++ ++ /* Expand first key: key = secret, data = 0x1 */ ++ output[0] = 1; ++ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, 1, BLAKE2S_OUTBYTES); ++ memcpy(first_dst, output, first_len); ++ ++ /* Expand second key: key = secret, data = first-key || 0x2 */ ++ output[BLAKE2S_OUTBYTES] = 2; ++ blake2s_hmac(output, output, secret, BLAKE2S_OUTBYTES, BLAKE2S_OUTBYTES + 1, BLAKE2S_OUTBYTES); ++ memcpy(second_dst, output, second_len); ++ ++ /* Clear sensitive data from stack */ ++ memzero_explicit(secret, BLAKE2S_OUTBYTES); ++ memzero_explicit(output, BLAKE2S_OUTBYTES + 1); ++} ++ ++static void symmetric_key_init(struct noise_symmetric_key *key) ++{ ++ spin_lock_init(&key->counter.receive.lock); ++ atomic64_set(&key->counter.counter, 0); ++ memset(key->counter.receive.backtrack, 0, sizeof(key->counter.receive.backtrack)); ++ key->birthdate = get_jiffies_64(); ++ key->is_valid = true; ++} ++ ++static void derive_keys(struct noise_symmetric_key *first_dst, struct noise_symmetric_key *second_dst, const u8 chaining_key[NOISE_HASH_LEN]) ++{ ++ kdf(first_dst->key, second_dst->key, NULL, NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, chaining_key); ++ symmetric_key_init(first_dst); ++ symmetric_key_init(second_dst); ++} ++ ++static void mix_key(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], const u8 *src, size_t src_len) ++{ ++ kdf(chaining_key, key, src, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, src_len, chaining_key); ++} ++ ++static void mix_dh(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], ++ const u8 private[NOISE_PUBLIC_KEY_LEN], const u8 public[NOISE_PUBLIC_KEY_LEN]) ++{ ++ u8 dh_calculation[NOISE_PUBLIC_KEY_LEN]; ++ curve25519(dh_calculation, private, public); ++ mix_key(key, chaining_key, dh_calculation, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(dh_calculation, NOISE_PUBLIC_KEY_LEN); ++} ++ ++static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len) ++{ ++ struct blake2s_state blake; ++ blake2s_init(&blake, NOISE_HASH_LEN); ++ blake2s_update(&blake, hash, NOISE_HASH_LEN); ++ blake2s_update(&blake, src, src_len); ++ blake2s_final(&blake, hash, NOISE_HASH_LEN); ++} ++ ++static void handshake_init(u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 chaining_key[NOISE_HASH_LEN], u8 hash[NOISE_HASH_LEN], ++ const u8 remote_static[NOISE_PUBLIC_KEY_LEN], const u8 psk[NOISE_SYMMETRIC_KEY_LEN]) ++{ ++ memset(key, 0, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(hash, psk ? handshake_psk_name_hash : handshake_name_hash, NOISE_HASH_LEN); ++ mix_hash(hash, identifier_name, sizeof(identifier_name)); ++ if (psk) { ++ u8 temp_hash[NOISE_HASH_LEN]; ++ kdf(chaining_key, temp_hash, psk, NOISE_HASH_LEN, NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, handshake_psk_name_hash); ++ mix_hash(hash, temp_hash, NOISE_HASH_LEN); ++ memzero_explicit(temp_hash, NOISE_HASH_LEN); ++ } else ++ memcpy(chaining_key, handshake_name_hash, NOISE_HASH_LEN); ++ mix_hash(hash, remote_static, NOISE_PUBLIC_KEY_LEN); ++} ++ ++static bool handshake_encrypt(u8 *dst_ciphertext, const u8 *src_plaintext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN]) ++{ ++ if (!chacha20poly1305_encrypt(dst_ciphertext, src_plaintext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key)) ++ return false; ++ mix_hash(hash, dst_ciphertext, noise_encrypted_len(src_len)); ++ return true; ++} ++ ++static bool handshake_decrypt(u8 *dst_plaintext, const u8 *src_ciphertext, size_t src_len, u8 key[NOISE_SYMMETRIC_KEY_LEN], u8 hash[NOISE_HASH_LEN]) ++{ ++ if (!chacha20poly1305_decrypt(dst_plaintext, src_ciphertext, src_len, hash, NOISE_HASH_LEN, 0 /* Always zero for Noise_IK */, key)) ++ return false; ++ mix_hash(hash, src_ciphertext, src_len); ++ return true; ++} ++ ++static void handshake_nocrypt(u8 *dst, const u8 *src, size_t src_len, u8 hash[NOISE_HASH_LEN]) ++{ ++ memcpy(dst, src, src_len); ++ mix_hash(hash, src, src_len); ++} ++ ++static void tai64n_now(u8 output[NOISE_TIMESTAMP_LEN]) ++{ ++ struct timeval now; ++ do_gettimeofday(&now); ++ /* https://cr.yp.to/libtai/tai64.html */ ++ *(__be64 *)output = cpu_to_be64(4611686018427387914ULL + now.tv_sec); ++ *(__be32 *)(output + sizeof(__be64)) = cpu_to_be32(1000 * now.tv_usec + 500); ++} ++ ++bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake) ++{ ++ u8 timestamp[NOISE_TIMESTAMP_LEN]; ++ bool ret = false; ++ ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (unlikely(!handshake->static_identity->has_identity)) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION); ++ ++ handshake_init(handshake->key, handshake->chaining_key, handshake->hash, handshake->remote_static, ++ handshake->static_identity->has_psk ? handshake->static_identity->preshared_key : NULL); ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private); ++ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash); ++ if (handshake->static_identity->has_psk) ++ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN); ++ ++ /* es */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static); ++ ++ /* s */ ++ if (!handshake_encrypt(dst->encrypted_static, handshake->static_identity->static_public, NOISE_PUBLIC_KEY_LEN, handshake->key, handshake->hash)) ++ goto out; ++ ++ /* ss */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->static_identity->static_private, handshake->remote_static); ++ ++ /* t */ ++ tai64n_now(timestamp); ++ if (!handshake_encrypt(dst->encrypted_timestamp, timestamp, NOISE_TIMESTAMP_LEN, handshake->key, handshake->hash)) ++ goto out; ++ ++ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ ++ ret = true; ++ handshake->state = HANDSHAKE_CREATED_INITIATION; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ return ret; ++} ++ ++struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg) ++{ ++ bool replay_attack, flood_attack; ++ u8 s[NOISE_PUBLIC_KEY_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 t[NOISE_TIMESTAMP_LEN]; ++ struct noise_handshake *handshake; ++ struct wireguard_peer *wg_peer = NULL; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ ++ down_read(&wg->static_identity.lock); ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake_init(key, chaining_key, hash, wg->static_identity.static_public, ++ wg->static_identity.has_psk ? wg->static_identity.preshared_key : NULL); ++ ++ /* e */ ++ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash); ++ if (wg->static_identity.has_psk) ++ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN); ++ ++ /* es */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, e); ++ ++ /* s */ ++ if (!handshake_decrypt(s, src->encrypted_static, sizeof(src->encrypted_static), key, hash)) ++ goto out; ++ ++ /* ss */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, s); ++ ++ /* t */ ++ if (!handshake_decrypt(t, src->encrypted_timestamp, sizeof(src->encrypted_timestamp), key, hash)) ++ goto out; ++ ++ /* Lookup which peer we're actually talking to */ ++ wg_peer = pubkey_hashtable_lookup(&wg->peer_hashtable, s); ++ if (!wg_peer) ++ goto out; ++ handshake = &wg_peer->handshake; ++ down_read(&handshake->lock); ++ replay_attack = memcmp(t, handshake->latest_timestamp, NOISE_TIMESTAMP_LEN) <= 0; ++ flood_attack = !time_is_before_jiffies64(handshake->last_initiation_consumption + INITIATIONS_PER_SECOND); ++ up_read(&handshake->lock); ++ if (replay_attack || flood_attack) { ++ peer_put(wg_peer); ++ wg_peer = NULL; ++ goto out; ++ } ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ memcpy(handshake->latest_timestamp, t, NOISE_TIMESTAMP_LEN); ++ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ handshake->last_initiation_consumption = get_jiffies_64(); ++ handshake->state = HANDSHAKE_CONSUMED_INITIATION; ++ up_write(&handshake->lock); ++ ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ up_read(&wg->static_identity.lock); ++ return wg_peer; ++} ++ ++bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *handshake) ++{ ++ bool ret = false; ++ down_read(&handshake->static_identity->lock); ++ down_write(&handshake->lock); ++ ++ if (handshake->state != HANDSHAKE_CONSUMED_INITIATION) ++ goto out; ++ ++ dst->header.type = cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE); ++ dst->receiver_index = handshake->remote_index; ++ ++ /* e */ ++ curve25519_generate_secret(handshake->ephemeral_private); ++ curve25519_generate_public(handshake->ephemeral_public, handshake->ephemeral_private); ++ handshake_nocrypt(dst->unencrypted_ephemeral, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN, handshake->hash); ++ if (handshake->static_identity->has_psk) ++ mix_key(handshake->key, handshake->chaining_key, handshake->ephemeral_public, NOISE_PUBLIC_KEY_LEN); ++ ++ /* ee */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_ephemeral); ++ ++ /* se */ ++ mix_dh(handshake->key, handshake->chaining_key, handshake->ephemeral_private, handshake->remote_static); ++ ++ if (!handshake_encrypt(dst->encrypted_nothing, NULL, 0, handshake->key, handshake->hash)) ++ goto out; ++ ++ dst->sender_index = index_hashtable_insert(&handshake->entry.peer->device->index_hashtable, &handshake->entry); ++ ++ handshake->state = HANDSHAKE_CREATED_RESPONSE; ++ ret = true; ++ ++out: ++ up_write(&handshake->lock); ++ up_read(&handshake->static_identity->lock); ++ return ret; ++} ++ ++struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg) ++{ ++ struct noise_handshake *handshake; ++ struct wireguard_peer *ret_peer = NULL; ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ u8 e[NOISE_PUBLIC_KEY_LEN]; ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ enum noise_handshake_state state = HANDSHAKE_ZEROED; ++ ++ down_read(&wg->static_identity.lock); ++ ++ if (unlikely(!wg->static_identity.has_identity)) ++ goto out; ++ ++ handshake = (struct noise_handshake *)index_hashtable_lookup(&wg->index_hashtable, INDEX_HASHTABLE_HANDSHAKE, src->receiver_index); ++ if (unlikely(!handshake)) ++ goto out; ++ ++ down_read(&handshake->lock); ++ state = handshake->state; ++ memcpy(key, handshake->key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(hash, handshake->hash, NOISE_HASH_LEN); ++ memcpy(chaining_key, handshake->chaining_key, NOISE_HASH_LEN); ++ memcpy(ephemeral_private, handshake->ephemeral_private, NOISE_PUBLIC_KEY_LEN); ++ up_read(&handshake->lock); ++ ++ if (state != HANDSHAKE_CREATED_INITIATION) ++ goto fail; ++ ++ /* e */ ++ handshake_nocrypt(e, src->unencrypted_ephemeral, sizeof(src->unencrypted_ephemeral), hash); ++ if (wg->static_identity.has_psk) ++ mix_key(key, chaining_key, e, NOISE_PUBLIC_KEY_LEN); ++ ++ /* ee */ ++ mix_dh(key, chaining_key, ephemeral_private, e); ++ ++ /* se */ ++ mix_dh(key, chaining_key, wg->static_identity.static_private, e); ++ ++ /* decrypt nothing */ ++ if (!handshake_decrypt(NULL, src->encrypted_nothing, sizeof(src->encrypted_nothing), key, hash)) ++ goto fail; ++ ++ /* Success! Copy everything to peer */ ++ down_write(&handshake->lock); ++ memcpy(handshake->remote_ephemeral, e, NOISE_PUBLIC_KEY_LEN); ++ memcpy(handshake->key, key, NOISE_SYMMETRIC_KEY_LEN); ++ memcpy(handshake->hash, hash, NOISE_HASH_LEN); ++ memcpy(handshake->chaining_key, chaining_key, NOISE_HASH_LEN); ++ handshake->remote_index = src->sender_index; ++ handshake->state = HANDSHAKE_CONSUMED_RESPONSE; ++ up_write(&handshake->lock); ++ ret_peer = handshake->entry.peer; ++ goto out; ++ ++fail: ++ peer_put(handshake->entry.peer); ++out: ++ memzero_explicit(key, NOISE_SYMMETRIC_KEY_LEN); ++ memzero_explicit(hash, NOISE_HASH_LEN); ++ memzero_explicit(chaining_key, NOISE_HASH_LEN); ++ memzero_explicit(ephemeral_private, NOISE_PUBLIC_KEY_LEN); ++ memzero_explicit(static_private, NOISE_PUBLIC_KEY_LEN); ++ up_read(&wg->static_identity.lock); ++ return ret_peer; ++} ++ ++bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator) ++{ ++ struct noise_keypair *new_keypair; ++ ++ down_read(&handshake->lock); ++ if (handshake->state != HANDSHAKE_CREATED_RESPONSE && handshake->state != HANDSHAKE_CONSUMED_RESPONSE) ++ goto fail; ++ ++ new_keypair = keypair_create(handshake->entry.peer); ++ if (!new_keypair) ++ goto fail; ++ new_keypair->i_am_the_initiator = i_am_the_initiator; ++ new_keypair->remote_index = handshake->remote_index; ++ ++ if (i_am_the_initiator) ++ derive_keys(&new_keypair->sending, &new_keypair->receiving, handshake->chaining_key); ++ else ++ derive_keys(&new_keypair->receiving, &new_keypair->sending, handshake->chaining_key); ++ up_read(&handshake->lock); ++ ++ add_new_keypair(keypairs, new_keypair); ++ index_hashtable_replace(&handshake->entry.peer->device->index_hashtable, &handshake->entry, &new_keypair->entry); ++ noise_handshake_clear(handshake); ++ net_dbg_ratelimited("Keypair %Lu created for peer %Lu\n", new_keypair->internal_id, new_keypair->entry.peer->internal_id); ++ ++ return true; ++ ++fail: ++ up_read(&handshake->lock); ++ return false; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/peer.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,151 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "peer.h" ++#include "device.h" ++#include "packets.h" ++#include "timers.h" ++#include "hashtables.h" ++#include "noise.h" ++ ++#include ++#include ++#include ++#include ++ ++static atomic64_t peer_counter = ATOMIC64_INIT(0); ++ ++struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN]) ++{ ++ struct wireguard_peer *peer; ++ lockdep_assert_held(&wg->device_update_lock); ++ ++ if (peer_total_count(wg) >= MAX_PEERS_PER_DEVICE) ++ return NULL; ++ ++ peer = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL); ++ if (!peer) ++ return NULL; ++ ++ if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL)) { ++ kfree(peer); ++ return NULL; ++ } ++ ++ peer->internal_id = atomic64_inc_return(&peer_counter); ++ peer->device = wg; ++ cookie_init(&peer->latest_cookie); ++ noise_handshake_init(&peer->handshake, &wg->static_identity, public_key, peer); ++ cookie_checker_precompute_keys(&wg->cookie_checker, peer); ++ mutex_init(&peer->keypairs.keypair_update_lock); ++ INIT_WORK(&peer->transmit_handshake_work, packet_send_queued_handshakes); ++ rwlock_init(&peer->endpoint_lock); ++ skb_queue_head_init(&peer->tx_packet_queue); ++ kref_init(&peer->refcount); ++ pubkey_hashtable_add(&wg->peer_hashtable, peer); ++ list_add_tail(&peer->peer_list, &wg->peer_list); ++ pr_debug("Peer %Lu created\n", peer->internal_id); ++ return peer; ++} ++ ++struct wireguard_peer *peer_get(struct wireguard_peer *peer) ++{ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "Calling peer_get without holding the RCU read lock."); ++ if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount))) ++ return NULL; ++ return peer; ++} ++ ++struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer) ++{ ++ rcu_read_lock(); ++ peer = peer_get(peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++/* We have a separate "remove" function to get rid of the final reference because ++ * peer_list, clearing handshakes, and flushing all require mutexes which requires ++ * sleeping, which must only be done from certain contexts. */ ++void peer_remove(struct wireguard_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ lockdep_assert_held(&peer->device->device_update_lock); ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ list_del(&peer->peer_list); ++ timers_uninit_peer(peer); ++ routing_table_remove_by_peer(&peer->device->peer_routing_table, peer); ++ pubkey_hashtable_remove(&peer->device->peer_hashtable, peer); ++ if (peer->device->workqueue) ++ flush_workqueue(peer->device->workqueue); ++ skb_queue_purge(&peer->tx_packet_queue); ++ peer_put(peer); ++} ++ ++static void rcu_release(struct rcu_head *rcu) ++{ ++ struct wireguard_peer *peer = container_of(rcu, struct wireguard_peer, rcu); ++ pr_debug("Peer %Lu (%pISpfsc) destroyed\n", peer->internal_id, &peer->endpoint.addr); ++ skb_queue_purge(&peer->tx_packet_queue); ++ dst_cache_destroy(&peer->endpoint_cache); ++ kzfree(peer); ++} ++ ++static void kref_release(struct kref *refcount) ++{ ++ struct wireguard_peer *peer = container_of(refcount, struct wireguard_peer, refcount); ++ call_rcu(&peer->rcu, rcu_release); ++} ++ ++void peer_put(struct wireguard_peer *peer) ++{ ++ if (unlikely(!peer)) ++ return; ++ kref_put(&peer->refcount, kref_release); ++} ++ ++int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data) ++{ ++ struct wireguard_peer *peer, *temp; ++ int ret = 0; ++ ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) { ++ peer = peer_rcu_get(peer); ++ if (unlikely(!peer)) ++ continue; ++ ret = fn(peer, data); ++ peer_put(peer); ++ if (ret < 0) ++ break; ++ } ++ return ret; ++} ++ ++int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data) ++{ ++ int ret; ++ mutex_lock(&wg->device_update_lock); ++ ret = peer_for_each_unlocked(wg, fn, data); ++ mutex_unlock(&wg->device_update_lock); ++ return ret; ++} ++ ++void peer_remove_all(struct wireguard_device *wg) ++{ ++ struct wireguard_peer *peer, *temp; ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) ++ peer_remove(peer); ++} ++ ++unsigned int peer_total_count(struct wireguard_device *wg) ++{ ++ unsigned int i = 0; ++ struct wireguard_peer *peer; ++ lockdep_assert_held(&wg->device_update_lock); ++ list_for_each_entry(peer, &wg->peer_list, peer_list) ++ ++i; ++ return i; ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/ratelimiter.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,138 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "ratelimiter.h" ++#include "peer.h" ++#include "device.h" ++ ++#include ++#include ++#include ++ ++static struct xt_match *v4_match __read_mostly; ++#if IS_ENABLED(CONFIG_IPV6) ++static struct xt_match *v6_match __read_mostly; ++#endif ++ ++enum { ++ RATELIMITER_PACKETS_PER_SECOND = 30, ++ RATELIMITER_PACKETS_BURSTABLE = 5 ++}; ++ ++static inline void cfg_init(struct hashlimit_cfg1 *cfg, int family) ++{ ++ memset(cfg, 0, sizeof(struct hashlimit_cfg1)); ++ if (family == NFPROTO_IPV4) ++ cfg->srcmask = 32; ++ else if (family == NFPROTO_IPV6) ++ cfg->srcmask = 96; ++ cfg->mode = XT_HASHLIMIT_HASH_SIP; /* source IP only -- we could also do source port by ORing this with XT_HASHLIMIT_HASH_SPT */ ++ cfg->avg = XT_HASHLIMIT_SCALE / RATELIMITER_PACKETS_PER_SECOND; /* 30 per second per IP */ ++ cfg->burst = RATELIMITER_PACKETS_BURSTABLE; /* Allow bursts of 5 at a time */ ++ cfg->gc_interval = 1000; /* same as expiration date */ ++ cfg->expire = 1000; /* Units of avg (seconds = 1) times 1000 */ ++ /* cfg->size and cfg->max are computed based on the memory size of left to zero */ ++} ++ ++int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg) ++{ ++ struct net_device *dev = netdev_pub(wg); ++ struct xt_mtchk_param chk = { .net = wg->creating_net }; ++ int ret; ++ ++ memset(ratelimiter, 0, sizeof(struct ratelimiter)); ++ ++ cfg_init(&ratelimiter->v4_info.cfg, NFPROTO_IPV4); ++ memcpy(ratelimiter->v4_info.name, dev->name, IFNAMSIZ); ++ chk.matchinfo = &ratelimiter->v4_info; ++ chk.match = v4_match; ++ chk.family = NFPROTO_IPV4; ++ ret = v4_match->checkentry(&chk); ++ if (ret < 0) ++ return ret; ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ cfg_init(&ratelimiter->v6_info.cfg, NFPROTO_IPV6); ++ memcpy(ratelimiter->v6_info.name, dev->name, IFNAMSIZ); ++ chk.matchinfo = &ratelimiter->v6_info; ++ chk.match = v6_match; ++ chk.family = NFPROTO_IPV6; ++ ret = v6_match->checkentry(&chk); ++ if (ret < 0) { ++ struct xt_mtdtor_param dtor_v4 = { ++ .net = wg->creating_net, ++ .match = v4_match, ++ .matchinfo = &ratelimiter->v4_info, ++ .family = NFPROTO_IPV4 ++ }; ++ v4_match->destroy(&dtor_v4); ++ return ret; ++ } ++#endif ++ ++ ratelimiter->net = wg->creating_net; ++ return 0; ++} ++ ++void ratelimiter_uninit(struct ratelimiter *ratelimiter) ++{ ++ struct xt_mtdtor_param dtor = { .net = ratelimiter->net }; ++ ++ dtor.match = v4_match; ++ dtor.matchinfo = &ratelimiter->v4_info; ++ dtor.family = NFPROTO_IPV4; ++ v4_match->destroy(&dtor); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ dtor.match = v6_match; ++ dtor.matchinfo = &ratelimiter->v6_info; ++ dtor.family = NFPROTO_IPV6; ++ v6_match->destroy(&dtor); ++#endif ++} ++ ++bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb) ++{ ++ struct xt_action_param action = { { NULL } }; ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return false; ++ if (ip_hdr(skb)->version == 4) { ++ action.match = v4_match; ++ action.matchinfo = &ratelimiter->v4_info; ++ action.thoff = ip_hdrlen(skb); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ else if (ip_hdr(skb)->version == 6) { ++ action.match = v6_match; ++ action.matchinfo = &ratelimiter->v6_info; ++ } ++#endif ++ else ++ return false; ++ return action.match->match(skb, &action); ++} ++ ++int ratelimiter_module_init(void) ++{ ++ v4_match = xt_request_find_match(NFPROTO_IPV4, "hashlimit", 1); ++ if (IS_ERR(v4_match)) { ++ pr_err("The xt_hashlimit module for IPv4 is required\n"); ++ return PTR_ERR(v4_match); ++ } ++#if IS_ENABLED(CONFIG_IPV6) ++ v6_match = xt_request_find_match(NFPROTO_IPV6, "hashlimit", 1); ++ if (IS_ERR(v6_match)) { ++ pr_err("The xt_hashlimit module for IPv6 is required\n"); ++ module_put(v4_match->me); ++ return PTR_ERR(v6_match); ++ } ++#endif ++ return 0; ++} ++ ++void ratelimiter_module_deinit(void) ++{ ++ module_put(v4_match->me); ++#if IS_ENABLED(CONFIG_IPV6) ++ module_put(v6_match->me); ++#endif ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/receive.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,311 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "device.h" ++#include "peer.h" ++#include "timers.h" ++#include "messages.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++ ++static inline void rx_stats(struct wireguard_peer *peer, size_t len) ++{ ++ struct pcpu_sw_netstats *tstats = get_cpu_ptr(netdev_pub(peer->device)->tstats); ++ u64_stats_update_begin(&tstats->syncp); ++ tstats->rx_bytes += len; ++ ++tstats->rx_packets; ++ u64_stats_update_end(&tstats->syncp); ++ put_cpu_ptr(tstats); ++ peer->rx_bytes += len; ++} ++ ++static inline void update_latest_addr(struct wireguard_peer *peer, struct sk_buff *skb) ++{ ++ struct endpoint endpoint; ++ if (!socket_endpoint_from_skb(&endpoint, skb)) ++ socket_set_peer_endpoint(peer, &endpoint); ++} ++ ++static inline int skb_data_offset(struct sk_buff *skb, size_t *data_offset, size_t *data_len) ++{ ++ struct udphdr *udp; ++ ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return -EINVAL; ++ if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6)) ++ return -EINVAL; ++ if (unlikely(ip_hdr(skb)->version == 6 && skb->len < sizeof(struct ipv6hdr))) ++ return -EINVAL; ++ ++ udp = udp_hdr(skb); ++ *data_offset = (u8 *)udp - skb->data; ++ if (unlikely(*data_offset > U16_MAX)) { ++ net_dbg_skb_ratelimited("Packet has offset at impossible location from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ if (unlikely(*data_offset + sizeof(struct udphdr) > skb->len)) { ++ net_dbg_skb_ratelimited("Packet isn't big enough to have UDP fields from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ *data_len = ntohs(udp->len); ++ if (unlikely(*data_len < sizeof(struct udphdr))) { ++ net_dbg_skb_ratelimited("UDP packet is reporting too small of a size from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ if (unlikely(*data_len > skb->len - *data_offset)) { ++ net_dbg_skb_ratelimited("UDP packet is lying about its size from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ *data_len -= sizeof(struct udphdr); ++ *data_offset = (u8 *)udp + sizeof(struct udphdr) - skb->data; ++ if (!pskb_may_pull(skb, *data_offset + sizeof(struct message_header))) { ++ net_dbg_skb_ratelimited("Could not pull header into data section from %pISpfsc\n", skb); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void receive_handshake_packet(struct wireguard_device *wg, void *data, size_t len, struct sk_buff *skb) ++{ ++ struct wireguard_peer *peer = NULL; ++ enum message_type message_type; ++ bool under_load; ++ enum cookie_mac_state mac_state; ++ bool packet_needs_cookie; ++ ++ message_type = message_determine_type(data, len); ++ ++ if (message_type == MESSAGE_HANDSHAKE_COOKIE) { ++ net_dbg_skb_ratelimited("Receiving cookie response from %pISpfsc\n", skb); ++ cookie_message_consume(data, wg); ++ return; ++ } ++ ++ under_load = skb_queue_len(&wg->incoming_handshakes) >= MAX_QUEUED_INCOMING_HANDSHAKES / 2; ++ mac_state = cookie_validate_packet(&wg->cookie_checker, skb, data, len, under_load); ++ if ((under_load && mac_state == VALID_MAC_WITH_COOKIE) || (!under_load && mac_state == VALID_MAC_BUT_NO_COOKIE)) ++ packet_needs_cookie = false; ++ else if (under_load && mac_state == VALID_MAC_BUT_NO_COOKIE) ++ packet_needs_cookie = true; ++ else { ++ net_dbg_skb_ratelimited("Invalid MAC of handshake, dropping packet from %pISpfsc\n", skb); ++ return; ++ } ++ ++ switch (message_type) { ++ case MESSAGE_HANDSHAKE_INITIATION: ++ if (packet_needs_cookie) { ++ struct message_handshake_initiation *message = data; ++ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index); ++ return; ++ } ++ peer = noise_handshake_consume_initiation(data, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("Invalid handshake initiation from %pISpfsc\n", skb); ++ return; ++ } ++ update_latest_addr(peer, skb); ++ net_dbg_ratelimited("Receiving handshake initiation from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ packet_send_handshake_response(peer); ++ break; ++ case MESSAGE_HANDSHAKE_RESPONSE: ++ if (packet_needs_cookie) { ++ struct message_handshake_response *message = data; ++ packet_send_handshake_cookie(wg, skb, message, sizeof(*message), message->sender_index); ++ return; ++ } ++ peer = noise_handshake_consume_response(data, wg); ++ if (unlikely(!peer)) { ++ net_dbg_skb_ratelimited("Invalid handshake response from %pISpfsc\n", skb); ++ return; ++ } ++ update_latest_addr(peer, skb); ++ net_dbg_ratelimited("Receiving handshake response from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, true)) { ++ timers_ephemeral_key_created(peer); ++ timers_handshake_complete(peer); ++ peer->sent_lastminute_handshake = false; ++ /* Calling this function will either send any existing packets in the queue ++ * and not send a keepalive, which is the best case, Or, if there's nothing ++ * in the queue, it will send a keepalive, in order to give immediate ++ * confirmation of the session. */ ++ packet_send_keepalive(peer); ++ } ++ break; ++ default: ++ WARN(1, "Somehow a wrong type of packet wound up in the handshake queue!\n"); ++ return; ++ } ++ ++ BUG_ON(!peer); ++ ++ rx_stats(peer, len); ++ timers_any_authenticated_packet_received(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ peer_put(peer); ++} ++ ++void packet_process_queued_handshake_packets(struct work_struct *work) ++{ ++ struct wireguard_device *wg = container_of(work, struct wireguard_device, incoming_handshakes_work); ++ struct sk_buff *skb; ++ size_t len, offset; ++ size_t num_processed = 0; ++ ++ while ((skb = skb_dequeue(&wg->incoming_handshakes)) != NULL) { ++ if (!skb_data_offset(skb, &offset, &len)) ++ receive_handshake_packet(wg, skb->data + offset, len, skb); ++ dev_kfree_skb(skb); ++ if (++num_processed == MAX_BURST_INCOMING_HANDSHAKES) { ++ queue_work(wg->workqueue, &wg->incoming_handshakes_work); ++ return; ++ } ++ } ++} ++ ++static void keep_key_fresh(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ if (peer->sent_lastminute_handshake) ++ return; ++ ++ rcu_read_lock(); ++ keypair = rcu_dereference(peer->keypairs.current_keypair); ++ if (likely(keypair && keypair->sending.is_valid) && keypair->i_am_the_initiator && ++ unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REJECT_AFTER_TIME - KEEPALIVE_TIMEOUT - REKEY_TIMEOUT))) ++ send = true; ++ rcu_read_unlock(); ++ ++ if (send) { ++ peer->sent_lastminute_handshake = true; ++ packet_queue_handshake_initiation(peer); ++ } ++} ++ ++struct packet_cb { ++ u8 ds; ++}; ++#define PACKET_CB(skb) ((struct packet_cb *)skb->cb) ++ ++static void receive_data_packet(struct sk_buff *skb, struct wireguard_peer *peer, struct endpoint *endpoint, bool used_new_key, int err) ++{ ++ struct net_device *dev; ++ struct wireguard_peer *routed_peer; ++ struct wireguard_device *wg; ++ ++ if (unlikely(err < 0 || !peer || !endpoint)) { ++ dev_kfree_skb(skb); ++ return; ++ } ++ ++ socket_set_peer_endpoint(peer, endpoint); ++ ++ wg = peer->device; ++ dev = netdev_pub(wg); ++ ++ if (unlikely(used_new_key)) { ++ peer->sent_lastminute_handshake = false; ++ packet_send_queue(peer); ++ } ++ ++ keep_key_fresh(peer); ++ ++ /* A packet with length 0 is a keepalive packet */ ++ if (unlikely(!skb->len)) { ++ net_dbg_ratelimited("Receiving keepalive packet from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ if (!pskb_may_pull(skb, 1 /* For checking the ip version below */)) { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_length_errors; ++ net_dbg_ratelimited("Packet missing IP version from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ skb->dev = dev; ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ if (skb->len >= sizeof(struct iphdr) && ip_hdr(skb)->version == 4) { ++ skb->protocol = htons(ETH_P_IP); ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP_ECN_set_ce(ip_hdr(skb)); ++ } else if (skb->len >= sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6) { ++ skb->protocol = htons(ETH_P_IPV6); ++ if (INET_ECN_is_ce(PACKET_CB(skb)->ds)) ++ IP6_ECN_set_ce(skb, ipv6_hdr(skb)); ++ } else { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_length_errors; ++ net_dbg_ratelimited("Packet neither ipv4 nor ipv6 from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ timers_data_received(peer); ++ ++ routed_peer = routing_table_lookup_src(&wg->peer_routing_table, skb); ++ peer_put(routed_peer); /* We don't need the extra reference. */ ++ ++ if (unlikely(routed_peer != peer)) { ++ ++dev->stats.rx_errors; ++ ++dev->stats.rx_frame_errors; ++ net_dbg_skb_ratelimited("Packet has unallowed src IP (%pISc) from peer %Lu (%pISpfsc)\n", skb, peer->internal_id, &peer->endpoint.addr); ++ goto packet_processed; ++ } ++ ++ if (likely(netif_rx(skb) == NET_RX_SUCCESS)) ++ rx_stats(peer, skb->len); ++ else { ++ ++dev->stats.rx_dropped; ++ net_dbg_ratelimited("Failed to give packet to userspace from peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ } ++ goto continue_processing; ++ ++packet_processed: ++ dev_kfree_skb(skb); ++continue_processing: ++ timers_any_authenticated_packet_received(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ peer_put(peer); ++} ++ ++void packet_receive(struct wireguard_device *wg, struct sk_buff *skb) ++{ ++ size_t len, offset; ++ ++ if (unlikely(skb_data_offset(skb, &offset, &len) < 0)) ++ goto err; ++ switch (message_determine_type(skb->data + offset, len)) { ++ case MESSAGE_HANDSHAKE_INITIATION: ++ case MESSAGE_HANDSHAKE_RESPONSE: ++ case MESSAGE_HANDSHAKE_COOKIE: ++ if (skb_queue_len(&wg->incoming_handshakes) > MAX_QUEUED_INCOMING_HANDSHAKES) { ++ net_dbg_skb_ratelimited("Too many handshakes queued, dropping packet from %pISpfsc\n", skb); ++ goto err; ++ } ++ if (skb_linearize(skb) < 0) { ++ net_dbg_skb_ratelimited("Unable to linearize handshake skb from %pISpfsc\n", skb); ++ goto err; ++ } ++ skb_queue_tail(&wg->incoming_handshakes, skb); ++ /* Queues up a call to packet_process_queued_handshake_packets(skb): */ ++ queue_work(wg->workqueue, &wg->incoming_handshakes_work); ++ break; ++ case MESSAGE_DATA: ++ PACKET_CB(skb)->ds = ip_tunnel_get_dsfield(ip_hdr(skb), skb); ++ packet_consume_data(skb, offset, wg, receive_data_packet); ++ break; ++ default: ++ net_dbg_skb_ratelimited("Invalid packet from %pISpfsc\n", skb); ++ goto err; ++ } ++ return; ++ ++err: ++ dev_kfree_skb(skb); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/routingtable.c 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,516 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "routingtable.h" ++#include "peer.h" ++ ++struct routing_table_node { ++ struct routing_table_node __rcu *bit[2]; ++ struct rcu_head rcu; ++ struct wireguard_peer *peer; ++ u8 cidr; ++ u8 bit_at_a, bit_at_b; ++ bool incidental; ++ u8 bits[]; ++}; ++ ++static inline u8 bit_at(const u8 *key, u8 a, u8 b) ++{ ++ return (key[a] >> b) & 1; ++} ++static inline void copy_and_assign_cidr(struct routing_table_node *node, const u8 *src, u8 cidr) ++{ ++ memcpy(node->bits, src, (cidr + 7) / 8); ++ node->bits[(cidr + 7) / 8 - 1] &= 0xff << ((8 - (cidr % 8)) % 8); ++ node->cidr = cidr; ++ node->bit_at_a = cidr / 8; ++ node->bit_at_b = 7 - (cidr % 8); ++} ++ ++/* Non-recursive RCU expansion of: ++ * ++ * free_node(node) ++ * { ++ * if (!node) ++ * return; ++ * free_node(node->bit[0]); ++ * free_node(node->bit[1]); ++ * kfree_rcu(node); ++ * } ++ */ ++#define ref(p) rcu_access_pointer(p) ++#define push(p) do { BUG_ON(len >= 128); stack[len++] = rcu_dereference_protected(p, lockdep_is_held(lock)); } while (0) ++static void free_node(struct routing_table_node *top, struct mutex *lock) ++{ ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node = NULL; ++ struct routing_table_node *prev = NULL; ++ unsigned int len = 0; ++ ++ if (!top) ++ return; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[len - 1]; ++ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) { ++ if (ref(node->bit[0])) ++ push(node->bit[0]); ++ else if (ref(node->bit[1])) ++ push(node->bit[1]); ++ } else if (ref(node->bit[0]) == prev) { ++ if (ref(node->bit[1])) ++ push(node->bit[1]); ++ } else { ++ kfree_rcu(node, rcu); ++ --len; ++ } ++ prev = node; ++ } ++} ++#undef push ++#define push(p) do { BUG_ON(len >= 128); stack[len++] = p; } while (0) ++static bool walk_remove_by_peer(struct routing_table_node __rcu **top, struct wireguard_peer *peer, struct mutex *lock) ++{ ++ struct routing_table_node __rcu **stack[128]; ++ struct routing_table_node __rcu **nptr; ++ struct routing_table_node *node = NULL; ++ struct routing_table_node *prev = NULL; ++ unsigned int len = 0; ++ bool ret = false; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ nptr = stack[len - 1]; ++ node = rcu_dereference_protected(*nptr, lockdep_is_held(lock)); ++ if (!node) { ++ --len; ++ continue; ++ } ++ if (!prev || ref(prev->bit[0]) == node || ref(prev->bit[1]) == node) { ++ if (ref(node->bit[0])) ++ push(&node->bit[0]); ++ else if (ref(node->bit[1])) ++ push(&node->bit[1]); ++ } else if (ref(node->bit[0]) == prev) { ++ if (ref(node->bit[1])) ++ push(&node->bit[1]); ++ } else { ++ if (node->peer == peer) { ++ ret = true; ++ node->peer = NULL; ++ node->incidental = true; ++ if (!node->bit[0] || !node->bit[1]) { ++ /* collapse (even if both are null) */ ++ rcu_assign_pointer(*nptr, rcu_dereference_protected(node->bit[!node->bit[0]], lockdep_is_held(lock))); ++ rcu_assign_pointer(node->bit[0], NULL); ++ rcu_assign_pointer(node->bit[1], NULL); ++ free_node(node, lock); ++ } ++ } ++ --len; ++ } ++ prev = node; ++ } ++ ++ return ret; ++} ++#undef ref ++#undef push ++ ++static inline bool match(const struct routing_table_node *node, const u8 *key, u8 match_len) ++{ ++ u8 full_blocks_to_match = match_len / 8; ++ u8 bits_leftover = match_len % 8; ++ u8 mask; ++ const u8 *a = node->bits, *b = key; ++ if (memcmp(a, b, full_blocks_to_match)) ++ return false; ++ if (!bits_leftover) ++ return true; ++ mask = ~(0xff >> bits_leftover); ++ return (a[full_blocks_to_match] & mask) == (b[full_blocks_to_match] & mask); ++} ++ ++static inline u8 common_bits(const struct routing_table_node *node, const u8 *key, u8 match_len) ++{ ++ u8 max = (((match_len > node->cidr) ? match_len : node->cidr) + 7) / 8; ++ u8 bits = 0; ++ u8 i, mask; ++ const u8 *a = node->bits, *b = key; ++ for (i = 0; i < max; ++i, bits += 8) { ++ if (a[i] != b[i]) ++ break; ++ } ++ if (i == max) ++ return bits; ++ for (mask = 128; mask > 0; mask /= 2, ++bits) { ++ if ((a[i] & mask) != (b[i] & mask)) ++ return bits; ++ } ++ BUG(); ++ return bits; ++} ++ ++static int remove(struct routing_table_node __rcu **trie, const u8 *key, u8 cidr, struct mutex *lock) ++{ ++ struct routing_table_node *parent = NULL, *node; ++ node = rcu_dereference_protected(*trie, lockdep_is_held(lock)); ++ while (node && node->cidr <= cidr && match(node, key, node->cidr)) { ++ if (node->cidr == cidr) { ++ /* exact match */ ++ node->incidental = true; ++ node->peer = NULL; ++ if (!node->bit[0] || !node->bit[1]) { ++ /* collapse (even if both are null) */ ++ if (parent) ++ rcu_assign_pointer(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], ++ rcu_dereference_protected(node->bit[(!node->bit[0]) ? 1 : 0], lockdep_is_held(lock))); ++ rcu_assign_pointer(node->bit[0], NULL); ++ rcu_assign_pointer(node->bit[1], NULL); ++ free_node(node, lock); ++ } ++ return 0; ++ } ++ parent = node; ++ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock)); ++ } ++ return -ENOENT; ++} ++ ++static inline struct routing_table_node *find_node(struct routing_table_node *trie, u8 bits, const u8 *key) ++{ ++ struct routing_table_node *node = trie, *found = NULL; ++ while (node && match(node, key, node->cidr)) { ++ if (!node->incidental) ++ found = node; ++ if (node->cidr == bits) ++ break; ++ node = rcu_dereference(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)]); ++ } ++ return found; ++} ++ ++static inline bool node_placement(struct routing_table_node __rcu *trie, const u8 *key, u8 cidr, struct routing_table_node **rnode, struct mutex *lock) ++{ ++ bool exact = false; ++ struct routing_table_node *parent = NULL, *node = rcu_dereference_protected(trie, lockdep_is_held(lock)); ++ while (node && node->cidr <= cidr && match(node, key, node->cidr)) { ++ parent = node; ++ if (parent->cidr == cidr) { ++ exact = true; ++ break; ++ } ++ node = rcu_dereference_protected(parent->bit[bit_at(key, parent->bit_at_a, parent->bit_at_b)], lockdep_is_held(lock)); ++ } ++ if (rnode) ++ *rnode = parent; ++ return exact; ++} ++ ++static int add(struct routing_table_node __rcu **trie, u8 bits, const u8 *key, u8 cidr, struct wireguard_peer *peer, struct mutex *lock) ++{ ++ struct routing_table_node *node, *parent, *down, *newnode; ++ ++ if (!rcu_access_pointer(*trie)) { ++ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!node) ++ return -ENOMEM; ++ node->peer = peer; ++ copy_and_assign_cidr(node, key, cidr); ++ rcu_assign_pointer(*trie, node); ++ return 0; ++ } ++ if (node_placement(*trie, key, cidr, &node, lock)) { ++ /* exact match */ ++ node->incidental = false; ++ node->peer = peer; ++ return 0; ++ } ++ ++ newnode = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!newnode) ++ return -ENOMEM; ++ newnode->peer = peer; ++ copy_and_assign_cidr(newnode, key, cidr); ++ ++ if (!node) ++ down = rcu_dereference_protected(*trie, lockdep_is_held(lock)); ++ else ++ down = rcu_dereference_protected(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], lockdep_is_held(lock)); ++ if (!down) { ++ rcu_assign_pointer(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)], newnode); ++ return 0; ++ } ++ /* here we must be inserting between node and down */ ++ cidr = min(cidr, common_bits(down, key, cidr)); ++ parent = node; ++ ++ /* we either need to make a new branch above down and newnode ++ * or newnode can be the branch. newnode can be the branch if ++ * its cidr == bits_in_common */ ++ if (newnode->cidr == cidr) { ++ /* newnode can be the branch */ ++ rcu_assign_pointer(newnode->bit[bit_at(down->bits, newnode->bit_at_a, newnode->bit_at_b)], down); ++ if (!parent) ++ rcu_assign_pointer(*trie, newnode); ++ else ++ rcu_assign_pointer(parent->bit[bit_at(newnode->bits, parent->bit_at_a, parent->bit_at_b)], newnode); ++ } else { ++ /* reparent */ ++ node = kzalloc(sizeof(*node) + (bits + 7) / 8, GFP_KERNEL); ++ if (!node) { ++ kfree(newnode); ++ return -ENOMEM; ++ } ++ node->incidental = true; ++ copy_and_assign_cidr(node, newnode->bits, cidr); ++ ++ rcu_assign_pointer(node->bit[bit_at(down->bits, node->bit_at_a, node->bit_at_b)], down); ++ rcu_assign_pointer(node->bit[bit_at(newnode->bits, node->bit_at_a, node->bit_at_b)], newnode); ++ if (!parent) ++ rcu_assign_pointer(*trie, node); ++ else ++ rcu_assign_pointer(parent->bit[bit_at(node->bits, parent->bit_at_a, parent->bit_at_b)], node); ++ } ++ return 0; ++} ++ ++#define push(p) do { \ ++ struct routing_table_node *next = (maybe_lock ? rcu_dereference_protected(p, lockdep_is_held(maybe_lock)) : rcu_dereference(p)); \ ++ if (next) { \ ++ BUG_ON(len >= 128); \ ++ stack[len++] = next; \ ++ } \ ++} while (0) ++static int walk_ips(struct routing_table_node *top, int family, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock) ++{ ++ int ret; ++ union nf_inet_addr ip = { .all = { 0 } }; ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node; ++ unsigned int len = 0; ++ struct wireguard_peer *peer; ++ ++ if (!top) ++ return 0; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[--len]; ++ ++ peer = peer_get(node->peer); ++ if (peer) { ++ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4); ++ ret = func(ctx, peer, ip, node->cidr, family); ++ peer_put(peer); ++ if (ret) ++ return ret; ++ } ++ ++ push(node->bit[0]); ++ push(node->bit[1]); ++ } ++ return 0; ++} ++static int walk_ips_by_peer(struct routing_table_node *top, int family, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family), struct mutex *maybe_lock) ++{ ++ int ret; ++ union nf_inet_addr ip = { .all = { 0 } }; ++ struct routing_table_node *stack[128]; ++ struct routing_table_node *node; ++ unsigned int len = 0; ++ ++ if (!top) ++ return 0; ++ ++ stack[len++] = top; ++ while (len > 0) { ++ node = stack[--len]; ++ ++ if (node->peer == peer) { ++ memcpy(ip.all, node->bits, family == AF_INET6 ? 16 : 4); ++ ret = func(ctx, ip, node->cidr, family); ++ if (ret) ++ return ret; ++ } ++ ++ push(node->bit[0]); ++ push(node->bit[1]); ++ } ++ return 0; ++} ++#undef push ++ ++void routing_table_init(struct routing_table *table) ++{ ++ memset(table, 0, sizeof(struct routing_table)); ++ mutex_init(&table->table_update_lock); ++} ++ ++void routing_table_free(struct routing_table *table) ++{ ++ mutex_lock(&table->table_update_lock); ++ free_node(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock); ++ rcu_assign_pointer(table->root4, NULL); ++ free_node(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), &table->table_update_lock); ++ rcu_assign_pointer(table->root6, NULL); ++ mutex_unlock(&table->table_update_lock); ++} ++ ++int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer) ++{ ++ int ret; ++ if (cidr > 32) ++ return -EINVAL; ++ mutex_lock(&table->table_update_lock); ++ ret = add(&table->root4, 32, (const u8 *)ip, cidr, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer) ++{ ++ int ret; ++ if (cidr > 128) ++ return -EINVAL; ++ mutex_lock(&table->table_update_lock); ++ ret = add(&table->root6, 128, (const u8 *)ip, cidr, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++/* Returns a strong reference to a peer */ ++inline struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip) ++{ ++ struct wireguard_peer *peer = NULL; ++ struct routing_table_node *node; ++ ++ rcu_read_lock(); ++ node = find_node(rcu_dereference(table->root4), 32, (const u8 *)ip); ++ if (node) ++ peer = peer_get(node->peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++/* Returns a strong reference to a peer */ ++inline struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip) ++{ ++ struct wireguard_peer *peer = NULL; ++ struct routing_table_node *node; ++ ++ rcu_read_lock(); ++ node = find_node(rcu_dereference(table->root6), 128, (const u8 *)ip); ++ if (node) ++ peer = peer_get(node->peer); ++ rcu_read_unlock(); ++ return peer; ++} ++ ++int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = remove(&table->root4, (const u8 *)ip, cidr, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = remove(&table->root6, (const u8 *)ip, cidr, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer) ++{ ++ bool found; ++ mutex_lock(&table->table_update_lock); ++ found = walk_remove_by_peer(&table->root4, peer, &table->table_update_lock) | walk_remove_by_peer(&table->root6, peer, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return found ? 0 : -EINVAL; ++} ++ ++/* Calls func with a strong reference to each peer, before putting it when the function has completed. ++ * It's thus up to the caller to call peer_put on it if it's going to be used elsewhere after or stored. */ ++int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ rcu_read_lock(); ++ ret = walk_ips(rcu_dereference(table->root4), AF_INET, ctx, func, NULL); ++ rcu_read_unlock(); ++ if (ret) ++ return ret; ++ rcu_read_lock(); ++ ret = walk_ips(rcu_dereference(table->root6), AF_INET6, ctx, func, NULL); ++ rcu_read_unlock(); ++ return ret; ++} ++ ++int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ rcu_read_lock(); ++ ret = walk_ips_by_peer(rcu_dereference(table->root4), AF_INET, ctx, peer, func, NULL); ++ rcu_read_unlock(); ++ if (ret) ++ return ret; ++ rcu_read_lock(); ++ ret = walk_ips_by_peer(rcu_dereference(table->root6), AF_INET6, ctx, peer, func, NULL); ++ rcu_read_unlock(); ++ return ret; ++} ++ ++int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)) ++{ ++ int ret; ++ mutex_lock(&table->table_update_lock); ++ ret = walk_ips_by_peer(rcu_dereference_protected(table->root4, lockdep_is_held(&table->table_update_lock)), AF_INET, ctx, peer, func, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ if (ret) ++ return ret; ++ mutex_lock(&table->table_update_lock); ++ ret = walk_ips_by_peer(rcu_dereference_protected(table->root6, lockdep_is_held(&table->table_update_lock)), AF_INET6, ctx, peer, func, &table->table_update_lock); ++ mutex_unlock(&table->table_update_lock); ++ return ret; ++} ++ ++static inline bool has_valid_ip_header(struct sk_buff *skb) ++{ ++ if (unlikely(skb->len < sizeof(struct iphdr))) ++ return false; ++ else if (unlikely(skb->len < sizeof(struct ipv6hdr) && ip_hdr(skb)->version == 6)) ++ return false; ++ else if (unlikely(ip_hdr(skb)->version != 4 && ip_hdr(skb)->version != 6)) ++ return false; ++ return true; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb) ++{ ++ if (unlikely(!has_valid_ip_header(skb))) ++ return NULL; ++ if (ip_hdr(skb)->version == 4) ++ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->daddr); ++ else if (ip_hdr(skb)->version == 6) ++ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->daddr); ++ return NULL; ++} ++ ++/* Returns a strong reference to a peer */ ++struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb) ++{ ++ if (unlikely(!has_valid_ip_header(skb))) ++ return NULL; ++ if (ip_hdr(skb)->version == 4) ++ return routing_table_lookup_v4(table, (struct in_addr *)&ip_hdr(skb)->saddr); ++ else if (ip_hdr(skb)->version == 6) ++ return routing_table_lookup_v6(table, &ipv6_hdr(skb)->saddr); ++ return NULL; ++} ++ ++#include "selftest/routing-table.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/send.c 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,192 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "packets.h" ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "messages.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void packet_send_handshake_initiation(struct wireguard_peer *peer) ++{ ++ struct message_handshake_initiation packet; ++ ++ down_write(&peer->handshake.lock); ++ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) { ++ up_write(&peer->handshake.lock); ++ return; /* This function is rate limited. */ ++ } ++ peer->last_sent_handshake = get_jiffies_64(); ++ up_write(&peer->handshake.lock); ++ ++ net_dbg_ratelimited("Sending handshake initiation to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ ++ if (noise_handshake_create_initiation(&packet, &peer->handshake)) { ++ cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ timers_any_authenticated_packet_traversal(peer); ++ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_initiation), HANDSHAKE_DSCP); ++ timers_handshake_initiated(peer); ++ } ++} ++ ++void packet_send_queued_handshakes(struct work_struct *work) ++{ ++ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, transmit_handshake_work); ++ packet_send_handshake_initiation(peer); ++ peer_put(peer); ++} ++ ++void packet_queue_handshake_initiation(struct wireguard_peer *peer) ++{ ++ /* First checking the timestamp here is just an optimization; it will ++ * be caught while properly locked inside the actual work queue. */ ++ if (!time_is_before_jiffies64(peer->last_sent_handshake + REKEY_TIMEOUT)) ++ return; ++ ++ peer = peer_rcu_get(peer); ++ if (unlikely(!peer)) ++ return; ++ ++ /* Queues up calling packet_send_queued_handshakes(peer), where we do a peer_put(peer) after: */ ++ if (!queue_work(peer->device->workqueue, &peer->transmit_handshake_work)) ++ peer_put(peer); /* If the work was already queued, we want to drop the extra reference */ ++} ++ ++void packet_send_handshake_response(struct wireguard_peer *peer) ++{ ++ struct message_handshake_response packet; ++ ++ net_dbg_ratelimited("Sending handshake response to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ peer->last_sent_handshake = get_jiffies_64(); ++ ++ if (noise_handshake_create_response(&packet, &peer->handshake)) { ++ cookie_add_mac_to_packet(&packet, sizeof(packet), peer); ++ if (noise_handshake_begin_session(&peer->handshake, &peer->keypairs, false)) { ++ timers_ephemeral_key_created(peer); ++ timers_any_authenticated_packet_traversal(peer); ++ socket_send_buffer_to_peer(peer, &packet, sizeof(struct message_handshake_response), HANDSHAKE_DSCP); ++ } ++ } ++} ++ ++void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index) ++{ ++ struct message_handshake_cookie packet; ++ ++ net_dbg_skb_ratelimited("Sending cookie response for denied handshake message for %pISpfsc\n", initiating_skb); ++ cookie_message_create(&packet, initiating_skb, data, data_len, sender_index, &wg->cookie_checker); ++ socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, sizeof(packet)); ++} ++ ++static inline void keep_key_fresh(struct wireguard_peer *peer) ++{ ++ struct noise_keypair *keypair; ++ bool send = false; ++ ++ rcu_read_lock(); ++ keypair = rcu_dereference(peer->keypairs.current_keypair); ++ if (likely(keypair && keypair->sending.is_valid) && ++ (unlikely(atomic64_read(&keypair->sending.counter.counter) > REKEY_AFTER_MESSAGES) || ++ (keypair->i_am_the_initiator && unlikely(time_is_before_eq_jiffies64(keypair->sending.birthdate + REKEY_AFTER_TIME))))) ++ send = true; ++ rcu_read_unlock(); ++ ++ if (send) ++ packet_queue_handshake_initiation(peer); ++} ++ ++void packet_send_keepalive(struct wireguard_peer *peer) ++{ ++ struct sk_buff *skb; ++ if (!skb_queue_len(&peer->tx_packet_queue)) { ++ skb = alloc_skb(DATA_PACKET_HEAD_ROOM + MESSAGE_MINIMUM_LENGTH, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return; ++ skb_reserve(skb, DATA_PACKET_HEAD_ROOM); ++ skb->dev = netdev_pub(peer->device); ++ skb_queue_tail(&peer->tx_packet_queue, skb); ++ net_dbg_ratelimited("Sending keepalive packet to peer %Lu (%pISpfsc)\n", peer->internal_id, &peer->endpoint.addr); ++ } ++ packet_send_queue(peer); ++} ++ ++static void message_create_data_done(struct sk_buff_head *queue, struct wireguard_peer *peer) ++{ ++ struct sk_buff *skb, *tmp; ++ bool is_keepalive, data_sent = false; ++ ++ timers_any_authenticated_packet_traversal(peer); ++ skb_queue_walk_safe(queue, skb, tmp) { ++ is_keepalive = skb->len == message_data_len(0); ++ if (likely(!socket_send_skb_to_peer(peer, skb, *(u8 *)skb->cb) && !is_keepalive)) ++ data_sent = true; ++ } ++ if (likely(data_sent)) ++ timers_data_sent(peer); ++ ++ keep_key_fresh(peer); ++ ++ if (unlikely(peer->need_resend_queue)) ++ packet_send_queue(peer); ++} ++ ++void packet_send_queue(struct wireguard_peer *peer) ++{ ++ struct sk_buff_head queue; ++ unsigned long flags; ++ ++ peer->need_resend_queue = false; ++ ++ /* Steal the current queue into our local one. */ ++ skb_queue_head_init(&queue); ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice_init(&peer->tx_packet_queue, &queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ ++ if (unlikely(!skb_queue_len(&queue))) ++ return; ++ ++ /* We submit it for encryption and sending. */ ++ switch (packet_create_data(&queue, peer, message_create_data_done)) { ++ case 0: ++ break; ++ case -EBUSY: ++ /* EBUSY happens when the parallel workers are all filled up, in which ++ * case we should requeue everything. */ ++ ++ /* First, we mark that we should try to do this later, when existing ++ * jobs are done. */ ++ peer->need_resend_queue = true; ++ ++ /* We stick the remaining skbs from local_queue at the top of the peer's ++ * queue again, setting the top of local_queue to be the skb that begins ++ * the requeueing. */ ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice(&queue, &peer->tx_packet_queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ break; ++ case -ENOKEY: ++ /* ENOKEY means that we don't have a valid session for the peer, which ++ * means we should initiate a session, but after requeuing like above. */ ++ ++ spin_lock_irqsave(&peer->tx_packet_queue.lock, flags); ++ skb_queue_splice(&queue, &peer->tx_packet_queue); ++ spin_unlock_irqrestore(&peer->tx_packet_queue.lock, flags); ++ ++ packet_queue_handshake_initiation(peer); ++ break; ++ default: ++ /* If we failed for any other reason, we want to just free the packets and ++ * forget about them. We do this unlocked, since we're the only ones with ++ * a reference to the local queue. */ ++ __skb_queue_purge(&queue); ++ } ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/socket.c 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,385 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "device.h" ++#include "peer.h" ++#include "socket.h" ++#include "packets.h" ++#include "messages.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++ struct flowi4 fl = { ++ .saddr = endpoint->src4.s_addr, ++ .daddr = endpoint->addr4.sin_addr.s_addr, ++ .fl4_dport = endpoint->addr4.sin_port, ++ .fl4_sport = htons(wg->incoming_port), ++ .flowi4_mark = wg->fwmark, ++ .flowi4_proto = IPPROTO_UDP ++ }; ++ struct rtable *rt = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb->next = skb->prev = NULL; ++ skb->dev = netdev_pub(wg); ++ ++ rcu_read_lock(); ++ sock = rcu_dereference(wg->sock4); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ if (cache) ++ rt = dst_cache_get_ip4(cache, &fl.saddr); ++ ++ if (!rt) { ++ security_sk_classify_flow(sock, flowi4_to_flowi(&fl)); ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ if (unlikely(IS_ERR(rt) && PTR_ERR(rt) == -EINVAL && fl.saddr)) { ++ endpoint->src4.s_addr = fl.saddr = 0; ++ if (cache) ++ dst_cache_reset(cache); ++ rt = ip_route_output_flow(sock_net(sock), &fl, sock); ++ } ++ if (unlikely(IS_ERR(rt))) { ++ ret = PTR_ERR(rt); ++ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(rt->dst.dev == skb->dev)) { ++ dst_release(&rt->dst); ++ ret = -ELOOP; ++ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip4(cache, &rt->dst, fl.saddr); ++ } ++ udp_tunnel_xmit_skb(rt, sock, skb, ++ fl.saddr, fl.daddr, ++ ds, ip4_dst_hoplimit(&rt->dst), 0, ++ fl.fl4_sport, fl.fl4_dport, ++ false, false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static inline int send6(struct wireguard_device *wg, struct sk_buff *skb, struct endpoint *endpoint, u8 ds, struct dst_cache *cache) ++{ ++#if IS_ENABLED(CONFIG_IPV6) ++ struct flowi6 fl = { ++ .saddr = endpoint->src6, ++ .daddr = endpoint->addr6.sin6_addr, ++ .fl6_dport = endpoint->addr6.sin6_port, ++ .fl6_sport = htons(wg->incoming_port), ++ .flowi6_mark = wg->fwmark, ++ .flowi6_oif = endpoint->addr6.sin6_scope_id, ++ .flowi6_proto = IPPROTO_UDP ++ /* TODO: addr->sin6_flowinfo */ ++ }; ++ struct dst_entry *dst = NULL; ++ struct sock *sock; ++ int ret = 0; ++ ++ skb->next = skb->prev = NULL; ++ skb->dev = netdev_pub(wg); ++ ++ rcu_read_lock(); ++ sock = rcu_dereference(wg->sock6); ++ ++ if (unlikely(!sock)) { ++ ret = -ENONET; ++ goto err; ++ } ++ ++ if (cache) ++ dst = dst_cache_get_ip6(cache, &fl.saddr); ++ ++ if (!dst) { ++ security_sk_classify_flow(sock, flowi6_to_flowi(&fl)); ++ if (unlikely(!ipv6_addr_any(&fl.saddr) && !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) { ++ endpoint->src6 = fl.saddr = in6addr_any; ++ if (cache) ++ dst_cache_reset(cache); ++ } ++ ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); ++ if (unlikely(ret)) { ++ net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr, ret); ++ goto err; ++ } else if (unlikely(dst->dev == skb->dev)) { ++ dst_release(dst); ++ ret = -ELOOP; ++ net_dbg_ratelimited("Avoiding routing loop to %pISpfsc\n", &endpoint->addr); ++ goto err; ++ } ++ if (cache) ++ dst_cache_set_ip6(cache, dst, &fl.saddr); ++ } ++ ++ udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, ++ &fl.saddr, &fl.daddr, ++ ds, ip6_dst_hoplimit(dst), 0, ++ fl.fl6_sport, fl.fl6_dport, ++ false); ++ goto out; ++ ++err: ++ kfree_skb(skb); ++out: ++ rcu_read_unlock(); ++ return ret; ++#else ++ return -EAFNOSUPPORT; ++#endif ++} ++ ++int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds) ++{ ++ size_t skb_len = skb->len; ++ int ret = -EAFNOSUPPORT; ++ ++ read_lock_bh(&peer->endpoint_lock); ++ if (peer->endpoint.addr.sa_family == AF_INET) ++ ret = send4(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache); ++ else if (peer->endpoint.addr.sa_family == AF_INET6) ++ ret = send6(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache); ++ if (likely(!ret)) ++ peer->tx_bytes += skb_len; ++ read_unlock_bh(&peer->endpoint_lock); ++ ++ return ret; ++} ++ ++int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *buffer, size_t len, u8 ds) ++{ ++ struct sk_buff *skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ skb_reserve(skb, SKB_HEADER_LEN); ++ memcpy(skb_put(skb, len), buffer, len); ++ return socket_send_skb_to_peer(peer, skb, ds); ++} ++ ++int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len) ++{ ++ int ret = 0; ++ struct sk_buff *skb; ++ struct endpoint endpoint; ++ ++ if (unlikely(!in_skb)) ++ return -EINVAL; ++ ret = socket_endpoint_from_skb(&endpoint, in_skb); ++ if (unlikely(ret < 0)) ++ return ret; ++ ++ skb = alloc_skb(len + SKB_HEADER_LEN, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ return -ENOMEM; ++ skb_reserve(skb, SKB_HEADER_LEN); ++ memcpy(skb_put(skb, len), out_buffer, len); ++ ++ if (endpoint.addr.sa_family == AF_INET) ++ ret = send4(wg, skb, &endpoint, 0, NULL); ++ else if (endpoint.addr.sa_family == AF_INET6) ++ ret = send6(wg, skb, &endpoint, 0, NULL); ++ else ++ ret = -EAFNOSUPPORT; ++ ++ return ret; ++} ++ ++int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb) ++{ ++ memset(endpoint, 0, sizeof(struct endpoint)); ++ if (ip_hdr(skb)->version == 4) { ++ endpoint->addr4.sin_family = AF_INET; ++ endpoint->addr4.sin_port = udp_hdr(skb)->source; ++ endpoint->addr4.sin_addr.s_addr = ip_hdr(skb)->saddr; ++ endpoint->src4.s_addr = ip_hdr(skb)->daddr; ++ } else if (ip_hdr(skb)->version == 6) { ++ endpoint->addr6.sin6_family = AF_INET6; ++ endpoint->addr6.sin6_port = udp_hdr(skb)->source; ++ endpoint->addr6.sin6_addr = ipv6_hdr(skb)->saddr; ++ endpoint->addr6.sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, skb->skb_iif); ++ /* TODO: endpoint->addr6.sin6_flowinfo */ ++ endpoint->src6 = ipv6_hdr(skb)->daddr; ++ } else ++ return -EINVAL; ++ return 0; ++} ++ ++void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint) ++{ ++ if (endpoint->addr.sa_family == AF_INET) { ++ read_lock_bh(&peer->endpoint_lock); ++ if (likely(peer->endpoint.addr4.sin_family == AF_INET && ++ peer->endpoint.addr4.sin_port == endpoint->addr4.sin_port && ++ peer->endpoint.addr4.sin_addr.s_addr == endpoint->addr4.sin_addr.s_addr && ++ peer->endpoint.src4.s_addr == endpoint->src4.s_addr)) ++ goto out; ++ read_unlock_bh(&peer->endpoint_lock); ++ write_lock_bh(&peer->endpoint_lock); ++ peer->endpoint.addr4 = endpoint->addr4; ++ peer->endpoint.src4 = endpoint->src4; ++ } else if (endpoint->addr.sa_family == AF_INET6) { ++ read_lock_bh(&peer->endpoint_lock); ++ if (likely(peer->endpoint.addr6.sin6_family == AF_INET6 && ++ peer->endpoint.addr6.sin6_port == endpoint->addr6.sin6_port && ++ /* TODO: peer->endpoint.addr6.sin6_flowinfo == endpoint->addr6.sin6_flowinfo && */ ++ ipv6_addr_equal(&peer->endpoint.addr6.sin6_addr, &endpoint->addr6.sin6_addr) && ++ peer->endpoint.addr6.sin6_scope_id == endpoint->addr6.sin6_scope_id && ++ ipv6_addr_equal(&peer->endpoint.src6, &endpoint->src6))) ++ goto out; ++ read_unlock_bh(&peer->endpoint_lock); ++ write_lock_bh(&peer->endpoint_lock); ++ peer->endpoint.addr6 = endpoint->addr6; ++ peer->endpoint.src6 = endpoint->src6; ++ } else ++ return; ++ dst_cache_reset(&peer->endpoint_cache); ++ write_unlock_bh(&peer->endpoint_lock); ++ return; ++out: ++ read_unlock_bh(&peer->endpoint_lock); ++} ++ ++void socket_clear_peer_endpoint_src(struct wireguard_peer *peer) ++{ ++ write_lock_bh(&peer->endpoint_lock); ++ memset(&peer->endpoint.src6, 0, sizeof(peer->endpoint.src6)); ++ dst_cache_reset(&peer->endpoint_cache); ++ write_unlock_bh(&peer->endpoint_lock); ++} ++ ++static int receive(struct sock *sk, struct sk_buff *skb) ++{ ++ struct wireguard_device *wg; ++ ++ if (unlikely(!sk)) ++ goto err; ++ wg = sk->sk_user_data; ++ if (unlikely(!wg)) ++ goto err; ++ packet_receive(wg, skb); ++ return 0; ++ ++err: ++ kfree_skb(skb); ++ return 0; ++} ++ ++static inline void sock_free(struct sock *sock) ++{ ++ if (unlikely(!sock)) ++ return; ++ sk_clear_memalloc(sock); ++ udp_tunnel_sock_release(sock->sk_socket); ++} ++ ++static inline void set_sock_opts(struct socket *sock) ++{ ++ sock->sk->sk_allocation = GFP_ATOMIC; ++ sock->sk->sk_sndbuf = INT_MAX; ++ sk_set_memalloc(sock->sk); ++} ++ ++int socket_init(struct wireguard_device *wg) ++{ ++ int ret = 0; ++ struct udp_tunnel_sock_cfg cfg = { ++ .sk_user_data = wg, ++ .encap_type = 1, ++ .encap_rcv = receive ++ }; ++ struct socket *new4 = NULL; ++ struct udp_port_cfg port4 = { ++ .family = AF_INET, ++ .local_ip.s_addr = htonl(INADDR_ANY), ++ .local_udp_port = htons(wg->incoming_port), ++ .use_udp_checksums = true ++ }; ++#if IS_ENABLED(CONFIG_IPV6) ++ int retries = 0; ++ struct socket *new6 = NULL; ++ struct udp_port_cfg port6 = { ++ .family = AF_INET6, ++ .local_ip6 = IN6ADDR_ANY_INIT, ++ .local_udp_port = htons(wg->incoming_port), ++ .use_udp6_tx_checksums = true, ++ .use_udp6_rx_checksums = true, ++ .ipv6_v6only = true ++ }; ++retry: ++#endif ++ ++ mutex_lock(&wg->socket_update_lock); ++ ++ if (rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock)) || ++ rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock))) { ++ ret = -EADDRINUSE; ++ goto out; ++ } ++ ++ ret = udp_sock_create(wg->creating_net, &port4, &new4); ++ if (ret < 0) { ++ pr_err("Could not create IPv4 socket\n"); ++ goto out; ++ } ++ wg->incoming_port = ntohs(inet_sk(new4->sk)->inet_sport); ++ ++ set_sock_opts(new4); ++ setup_udp_tunnel_sock(wg->creating_net, new4, &cfg); ++ rcu_assign_pointer(wg->sock4, new4->sk); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (!ipv6_mod_enabled()) ++ goto out; ++ port6.local_udp_port = htons(wg->incoming_port); ++ ret = udp_sock_create(wg->creating_net, &port6, &new6); ++ if (ret < 0) { ++ udp_tunnel_sock_release(new4); ++ rcu_assign_pointer(wg->sock4, NULL); ++ if (ret == -EADDRINUSE && !port4.local_udp_port && retries++ < 100) ++ goto retry; ++ if (!port4.local_udp_port) ++ wg->incoming_port = 0; ++ pr_err("Could not create IPv6 socket\n"); ++ goto out; ++ } ++ set_sock_opts(new6); ++ setup_udp_tunnel_sock(wg->creating_net, new6, &cfg); ++ rcu_assign_pointer(wg->sock6, new6->sk); ++#endif ++ ++out: ++ mutex_unlock(&wg->socket_update_lock); ++ return ret; ++} ++ ++void socket_uninit(struct wireguard_device *wg) ++{ ++ struct sock *old4, *old6; ++ mutex_lock(&wg->socket_update_lock); ++ old4 = rcu_dereference_protected(wg->sock4, lockdep_is_held(&wg->socket_update_lock)); ++ old6 = rcu_dereference_protected(wg->sock6, lockdep_is_held(&wg->socket_update_lock)); ++ rcu_assign_pointer(wg->sock4, NULL); ++ rcu_assign_pointer(wg->sock6, NULL); ++ mutex_unlock(&wg->socket_update_lock); ++ synchronize_rcu(); ++ synchronize_net(); ++ sock_free(old4); ++ sock_free(old6); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/timers.c 2017-03-05 17:03:41.529682426 +0200 +@@ -0,0 +1,178 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#include "timers.h" ++#include "device.h" ++#include "peer.h" ++#include "packets.h" ++ ++/* ++ * Timer for retransmitting the handshake if we don't hear back after `REKEY_TIMEOUT` ms ++ * Timer for sending empty packet if we have received a packet but after have not sent one for `KEEPALIVE_TIMEOUT` ms ++ * Timer for initiating new handshake if we have sent a packet but after have not received one (even empty) for `(KEEPALIVE_TIMEOUT + REKEY_TIMEOUT)` ms ++ * Timer for zeroing out all ephemeral keys after `(REJECT_AFTER_TIME * 3)` ms if no new keys have been received ++ * Timer for, if enabled, sending an empty authenticated packet every user-specified seconds ++ */ ++ ++/* This rounds the time down to the closest power of two of the closest quarter second. */ ++static inline unsigned long slack_time(unsigned long time) ++{ ++ return time & ~(roundup_pow_of_two(HZ / 4) - 1); ++} ++ ++#define peer_get_from_ptr(ptr) \ ++ struct wireguard_peer *peer = peer_rcu_get((struct wireguard_peer *)ptr); \ ++ if (unlikely(!peer)) \ ++ return; ++ ++static void expired_retransmit_handshake(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ pr_debug("Handshake for peer %Lu (%pISpfsc) did not complete after %d seconds, retrying\n", peer->internal_id, &peer->endpoint.addr, REKEY_TIMEOUT / HZ); ++ if (peer->timer_handshake_attempts > MAX_TIMER_HANDSHAKES) { ++ del_timer(&peer->timer_send_keepalive); ++ /* We remove all existing packets and don't try again, ++ * if we try unsuccessfully for too long to make a handshake. */ ++ skb_queue_purge(&peer->tx_packet_queue); ++ /* We set a timer for destroying any residue that might be left ++ * of a partial exchange. */ ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3)); ++ goto out; ++ } ++ ++ /* We clear the endpoint address src address, in case this is the cause of trouble. */ ++ socket_clear_peer_endpoint_src(peer); ++ ++ packet_queue_handshake_initiation(peer); ++ ++peer->timer_handshake_attempts; ++out: ++ peer_put(peer); ++} ++ ++static void expired_send_keepalive(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ packet_send_keepalive(peer); ++ if (peer->timer_need_another_keepalive) { ++ peer->timer_need_another_keepalive = false; ++ if (peer->timers_enabled) ++ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT); ++ } ++ peer_put(peer); ++} ++ ++static void expired_new_handshake(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ pr_debug("Retrying handshake with peer %Lu (%pISpfsc) because we stopped hearing back after %d seconds\n", peer->internal_id, &peer->endpoint.addr, (KEEPALIVE_TIMEOUT + REKEY_TIMEOUT) / HZ); ++ /* We clear the endpoint address src address, in case this is the cause of trouble. */ ++ socket_clear_peer_endpoint_src(peer); ++ packet_queue_handshake_initiation(peer); ++ peer_put(peer); ++} ++ ++static void expired_kill_ephemerals(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ if (!queue_work(peer->device->workqueue, &peer->clear_peer_work)) /* Takes our reference. */ ++ peer_put(peer); /* If the work was already on the queue, we want to drop the extra reference */ ++} ++static void queued_expired_kill_ephemerals(struct work_struct *work) ++{ ++ struct wireguard_peer *peer = container_of(work, struct wireguard_peer, clear_peer_work); ++ pr_debug("Zeroing out all keys for peer %Lu (%pISpfsc), since we haven't received a new one in %d seconds\n", peer->internal_id, &peer->endpoint.addr, (REJECT_AFTER_TIME * 3) / HZ); ++ noise_handshake_clear(&peer->handshake); ++ noise_keypairs_clear(&peer->keypairs); ++ peer_put(peer); ++} ++ ++static void expired_send_persistent_keepalive(unsigned long ptr) ++{ ++ peer_get_from_ptr(ptr); ++ if (likely(peer->persistent_keepalive_interval)) ++ packet_send_keepalive(peer); ++ peer_put(peer); ++} ++ ++/* Should be called after an authenticated data packet is sent. */ ++void timers_data_sent(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_send_keepalive); ++ ++ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_new_handshake)) ++ mod_timer(&peer->timer_new_handshake, jiffies + KEEPALIVE_TIMEOUT + REKEY_TIMEOUT); ++} ++ ++/* Should be called after an authenticated data packet is received. */ ++void timers_data_received(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled) && !timer_pending(&peer->timer_send_keepalive)) ++ mod_timer(&peer->timer_send_keepalive, jiffies + KEEPALIVE_TIMEOUT); ++ else ++ peer->timer_need_another_keepalive = true; ++} ++ ++/* Should be called after any type of authenticated packet is received -- keepalive or data. */ ++void timers_any_authenticated_packet_received(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_new_handshake); ++} ++ ++/* Should be called after a handshake initiation message is sent. */ ++void timers_handshake_initiated(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_send_keepalive); ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_retransmit_handshake, slack_time(jiffies + REKEY_TIMEOUT + prandom_u32_max(REKEY_TIMEOUT_JITTER_MAX))); ++} ++ ++/* Should be called after a handshake response message is received and processed. */ ++void timers_handshake_complete(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ del_timer(&peer->timer_retransmit_handshake); ++ peer->timer_handshake_attempts = 0; ++} ++ ++/* Should be called after an ephemeral key is created, which is before sending a handshake response or after receiving a handshake response. */ ++void timers_ephemeral_key_created(struct wireguard_peer *peer) ++{ ++ if (likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_kill_ephemerals, jiffies + (REJECT_AFTER_TIME * 3)); ++ do_gettimeofday(&peer->walltime_last_handshake); ++} ++ ++/* Should be called before an packet with authentication -- data, keepalive, either handshake -- is sent, or after one is received. */ ++void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer) ++{ ++ if (peer->persistent_keepalive_interval && likely(peer->timers_enabled)) ++ mod_timer(&peer->timer_persistent_keepalive, slack_time(jiffies + peer->persistent_keepalive_interval)); ++} ++ ++void timers_init_peer(struct wireguard_peer *peer) ++{ ++ peer->timers_enabled = true; ++ setup_timer(&peer->timer_retransmit_handshake, expired_retransmit_handshake, (unsigned long)peer); ++ setup_timer(&peer->timer_send_keepalive, expired_send_keepalive, (unsigned long)peer); ++ setup_timer(&peer->timer_new_handshake, expired_new_handshake, (unsigned long)peer); ++ setup_timer(&peer->timer_kill_ephemerals, expired_kill_ephemerals, (unsigned long)peer); ++ setup_timer(&peer->timer_persistent_keepalive, expired_send_persistent_keepalive, (unsigned long)peer); ++ INIT_WORK(&peer->clear_peer_work, queued_expired_kill_ephemerals); ++} ++ ++void timers_uninit_peer(struct wireguard_peer *peer) ++{ ++ if (!peer->timers_enabled) ++ return; ++ peer->timers_enabled = false; ++ wmb(); ++ del_timer_sync(&peer->timer_retransmit_handshake); ++ del_timer_sync(&peer->timer_send_keepalive); ++ del_timer_sync(&peer->timer_new_handshake); ++ del_timer_sync(&peer->timer_kill_ephemerals); ++ del_timer_sync(&peer->timer_persistent_keepalive); ++ flush_work(&peer->clear_peer_work); ++} +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/config.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,11 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGCONFIG_H ++#define WGCONFIG_H ++ ++struct wireguard_device; ++ ++int config_get_device(struct wireguard_device *wg, void __user *udevice); ++int config_set_device(struct wireguard_device *wg, void __user *udevice); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/cookie.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,51 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGCOOKIE_H ++#define WGCOOKIE_H ++ ++#include "messages.h" ++#include "ratelimiter.h" ++#include ++ ++struct wireguard_peer; ++struct wireguard_device; ++struct sk_buff; ++ ++struct cookie_checker { ++ u8 secret[NOISE_HASH_LEN]; ++ u8 cookie_encryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ u64 secret_birthdate; ++ struct rw_semaphore secret_lock; ++ struct ratelimiter ratelimiter; ++ struct wireguard_device *device; ++}; ++ ++struct cookie { ++ u64 birthdate; ++ bool is_valid; ++ u8 cookie[COOKIE_LEN]; ++ bool have_sent_mac1; ++ u8 last_mac1_sent[COOKIE_LEN]; ++ u8 cookie_decryption_key[NOISE_SYMMETRIC_KEY_LEN]; ++ struct rw_semaphore lock; ++}; ++ ++enum cookie_mac_state { ++ INVALID_MAC, ++ VALID_MAC_BUT_NO_COOKIE, ++ VALID_MAC_WITH_COOKIE_BUT_RATELIMITED, ++ VALID_MAC_WITH_COOKIE ++}; ++ ++int cookie_checker_init(struct cookie_checker *checker, struct wireguard_device *wg); ++void cookie_checker_uninit(struct cookie_checker *checker); ++void cookie_checker_precompute_keys(struct cookie_checker *checker, struct wireguard_peer *peer); ++void cookie_init(struct cookie *cookie); ++ ++enum cookie_mac_state cookie_validate_packet(struct cookie_checker *checker, struct sk_buff *skb, void *data_start, size_t data_len, bool check_cookie); ++void cookie_add_mac_to_packet(void *message, size_t len, struct wireguard_peer *peer); ++ ++void cookie_message_create(struct message_handshake_cookie *src, struct sk_buff *skb, void *data_start, size_t data_len, __le32 index, struct cookie_checker *checker); ++void cookie_message_consume(struct message_handshake_cookie *src, struct wireguard_device *wg); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/device.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,45 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGDEVICE_H ++#define WGDEVICE_H ++ ++#include "noise.h" ++#include "routingtable.h" ++#include "hashtables.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct wireguard_device { ++ struct sock __rcu *sock4, *sock6; ++ u16 incoming_port; ++ u32 fwmark; ++ struct net *creating_net; ++ struct workqueue_struct *workqueue; ++ struct workqueue_struct *parallelqueue; ++ struct padata_instance *parallel_send, *parallel_receive; ++ struct noise_static_identity static_identity; ++ struct sk_buff_head incoming_handshakes; ++ struct work_struct incoming_handshakes_work; ++ struct cookie_checker cookie_checker; ++ struct pubkey_hashtable peer_hashtable; ++ struct index_hashtable index_hashtable; ++ struct routing_table peer_routing_table; ++ struct list_head peer_list; ++ struct mutex device_update_lock; ++ struct mutex socket_update_lock; ++#ifdef CONFIG_PM_SLEEP ++ struct notifier_block clear_peers_on_suspend; ++#endif ++}; ++ ++int device_init(void); ++void device_uninit(void); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/hashtables.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,48 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef HASHTABLES_H ++#define HASHTABLES_H ++ ++#include "messages.h" ++ ++#include ++#include ++#include ++ ++struct wireguard_peer; ++ ++struct pubkey_hashtable { ++ DECLARE_HASHTABLE(hashtable, 8); ++ siphash_key_t key; ++ struct mutex lock; ++}; ++ ++void pubkey_hashtable_init(struct pubkey_hashtable *table); ++void pubkey_hashtable_add(struct pubkey_hashtable *table, struct wireguard_peer *peer); ++void pubkey_hashtable_remove(struct pubkey_hashtable *table, struct wireguard_peer *peer); ++struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, const u8 pubkey[NOISE_PUBLIC_KEY_LEN]); ++ ++struct index_hashtable { ++ DECLARE_HASHTABLE(hashtable, 10); ++ siphash_key_t key; ++ spinlock_t lock; ++}; ++ ++enum index_hashtable_type { ++ INDEX_HASHTABLE_HANDSHAKE = (1 << 0), ++ INDEX_HASHTABLE_KEYPAIR = (1 << 1) ++}; ++ ++struct index_hashtable_entry { ++ struct wireguard_peer *peer; ++ struct hlist_node index_hash; ++ enum index_hashtable_type type; ++ __le32 index; ++}; ++void index_hashtable_init(struct index_hashtable *table); ++__le32 index_hashtable_insert(struct index_hashtable *table, struct index_hashtable_entry *entry); ++void index_hashtable_replace(struct index_hashtable *table, struct index_hashtable_entry *old, struct index_hashtable_entry *new); ++void index_hashtable_remove(struct index_hashtable *table, struct index_hashtable_entry *entry); ++struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *table, const enum index_hashtable_type type_mask, const __le32 index); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/messages.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * See doc/protocol.md for more info ++ */ ++ ++#ifndef MESSAGES_H ++#define MESSAGES_H ++ ++#include "crypto/curve25519.h" ++#include "crypto/chacha20poly1305.h" ++#include "crypto/blake2s.h" ++ ++#include ++#include ++ ++enum noise_lengths { ++ NOISE_PUBLIC_KEY_LEN = CURVE25519_POINT_SIZE, ++ NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEYLEN, ++ NOISE_TIMESTAMP_LEN = sizeof(u64) + sizeof(u32), ++ NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAGLEN, ++ NOISE_HASH_LEN = BLAKE2S_OUTBYTES ++}; ++ ++#define noise_encrypted_len(plain_len) (plain_len + NOISE_AUTHTAG_LEN) ++ ++enum cookie_values { ++ COOKIE_SECRET_MAX_AGE = 2 * 60 * HZ, ++ COOKIE_SECRET_LATENCY = 5 * HZ, ++ COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCELEN, ++ COOKIE_LEN = 16 ++}; ++ ++enum counter_values { ++ COUNTER_BITS_TOTAL = 2048, ++ COUNTER_REDUNDANT_BITS = BITS_PER_LONG, ++ COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS ++}; ++ ++enum limits { ++ REKEY_AFTER_MESSAGES = U64_MAX - 0xffff, ++ REJECT_AFTER_MESSAGES = U64_MAX - COUNTER_WINDOW_SIZE - 1, ++ REKEY_TIMEOUT = 5 * HZ, ++ REKEY_TIMEOUT_JITTER_MAX = HZ / 3, ++ REKEY_AFTER_TIME = 120 * HZ, ++ REJECT_AFTER_TIME = 180 * HZ, ++ INITIATIONS_PER_SECOND = HZ / 50, ++ MAX_PEERS_PER_DEVICE = U16_MAX, ++ KEEPALIVE_TIMEOUT = 10 * HZ, ++ MAX_TIMER_HANDSHAKES = (90 * HZ) / REKEY_TIMEOUT, ++ MAX_QUEUED_INCOMING_HANDSHAKES = 4096, ++ MAX_BURST_INCOMING_HANDSHAKES = 16, ++ MAX_QUEUED_OUTGOING_PACKETS = 1024 ++}; ++ ++enum message_type { ++ MESSAGE_INVALID = 0, ++ MESSAGE_HANDSHAKE_INITIATION = 1, ++ MESSAGE_HANDSHAKE_RESPONSE = 2, ++ MESSAGE_HANDSHAKE_COOKIE = 3, ++ MESSAGE_DATA = 4, ++ MESSAGE_TOTAL = 5 ++}; ++ ++struct message_header { ++ /* The actual layout of this that we want is: ++ * u8 type ++ * u8 reserved_zero[3] ++ * ++ * But it turns out that by encoding this as little endian, ++ * we achieve the same thing, and it makes checking faster. ++ */ ++ __le32 type; ++}; ++ ++struct message_macs { ++ u8 mac1[COOKIE_LEN]; ++ u8 mac2[COOKIE_LEN]; ++}; ++ ++struct message_handshake_initiation { ++ struct message_header header; ++ __le32 sender_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)]; ++ u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_response { ++ struct message_header header; ++ __le32 sender_index; ++ __le32 receiver_index; ++ u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ u8 encrypted_nothing[noise_encrypted_len(0)]; ++ struct message_macs macs; ++}; ++ ++struct message_handshake_cookie { ++ struct message_header header; ++ __le32 receiver_index; ++ u8 nonce[COOKIE_NONCE_LEN]; ++ u8 encrypted_cookie[noise_encrypted_len(COOKIE_LEN)]; ++}; ++ ++struct message_data { ++ struct message_header header; ++ __le32 key_idx; ++ __le64 counter; ++ u8 encrypted_data[]; ++}; ++ ++#define message_data_len(plain_len) (noise_encrypted_len(plain_len) + sizeof(struct message_data)) ++ ++enum message_alignments { ++ MESSAGE_PADDING_MULTIPLE = 16, ++ MESSAGE_MINIMUM_LENGTH = message_data_len(0) ++}; ++ ++#define SKB_HEADER_LEN (max(sizeof(struct iphdr), sizeof(struct ipv6hdr)) + sizeof(struct udphdr) + NET_SKB_PAD) ++#define DATA_PACKET_HEAD_ROOM ALIGN(sizeof(struct message_data) + SKB_HEADER_LEN, 4) ++ ++enum { ++ HANDSHAKE_DSCP = 0b10001000 /* AF41, plus 00 ECN */ ++}; ++ ++static inline enum message_type message_determine_type(void *src, size_t src_len) ++{ ++ struct message_header *header = src; ++ if (unlikely(src_len < sizeof(struct message_header))) ++ return MESSAGE_INVALID; ++ if (header->type == cpu_to_le32(MESSAGE_DATA) && src_len >= MESSAGE_MINIMUM_LENGTH) ++ return MESSAGE_DATA; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_INITIATION) && src_len == sizeof(struct message_handshake_initiation)) ++ return MESSAGE_HANDSHAKE_INITIATION; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_RESPONSE) && src_len == sizeof(struct message_handshake_response)) ++ return MESSAGE_HANDSHAKE_RESPONSE; ++ if (header->type == cpu_to_le32(MESSAGE_HANDSHAKE_COOKIE) && src_len == sizeof(struct message_handshake_cookie)) ++ return MESSAGE_HANDSHAKE_COOKIE; ++ return MESSAGE_INVALID; ++} ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/noise.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * See doc/protocol.md and https://github.com/trevp/noise/blob/master/noise.md for more info ++ */ ++ ++#ifndef NOISE_H ++#define NOISE_H ++ ++#include "messages.h" ++#include "hashtables.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++union noise_counter { ++ struct { ++ u64 counter; ++ unsigned long backtrack[COUNTER_BITS_TOTAL / BITS_PER_LONG]; ++ spinlock_t lock; ++ } receive; ++ atomic64_t counter; ++}; ++ ++struct noise_symmetric_key { ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ union noise_counter counter; ++ u64 birthdate; ++ bool is_valid; ++}; ++ ++struct noise_keypair { ++ struct index_hashtable_entry entry; ++ struct noise_symmetric_key sending; ++ struct noise_symmetric_key receiving; ++ __le32 remote_index; ++ bool i_am_the_initiator; ++ struct kref refcount; ++ struct rcu_head rcu; ++ u64 internal_id; ++}; ++ ++struct noise_keypairs { ++ struct noise_keypair __rcu *current_keypair; ++ struct noise_keypair __rcu *previous_keypair; ++ struct noise_keypair __rcu *next_keypair; ++ struct mutex keypair_update_lock; ++}; ++ ++struct noise_static_identity { ++ bool has_identity, has_psk; ++ u8 static_public[NOISE_PUBLIC_KEY_LEN]; ++ u8 static_private[NOISE_PUBLIC_KEY_LEN]; ++ u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]; ++ struct rw_semaphore lock; ++}; ++ ++enum noise_handshake_state { ++ HANDSHAKE_ZEROED, ++ HANDSHAKE_CREATED_INITIATION, ++ HANDSHAKE_CONSUMED_INITIATION, ++ HANDSHAKE_CREATED_RESPONSE, ++ HANDSHAKE_CONSUMED_RESPONSE ++}; ++ ++struct noise_handshake { ++ struct index_hashtable_entry entry; ++ ++ enum noise_handshake_state state; ++ u64 last_initiation_consumption; ++ ++ struct noise_static_identity *static_identity; ++ ++ u8 ephemeral_public[NOISE_PUBLIC_KEY_LEN]; ++ u8 ephemeral_private[NOISE_PUBLIC_KEY_LEN]; ++ ++ u8 remote_static[NOISE_PUBLIC_KEY_LEN]; ++ u8 remote_ephemeral[NOISE_PUBLIC_KEY_LEN]; ++ ++ u8 key[NOISE_SYMMETRIC_KEY_LEN]; ++ u8 hash[NOISE_HASH_LEN]; ++ u8 chaining_key[NOISE_HASH_LEN]; ++ ++ u8 latest_timestamp[NOISE_TIMESTAMP_LEN]; ++ __le32 remote_index; ++ ++ /* Protects all members except the immutable (after noise_peer_init): remote_static, static_identity */ ++ struct rw_semaphore lock; ++}; ++ ++struct wireguard_peer; ++struct wireguard_device; ++struct message_header; ++struct message_handshake_initiation; ++struct message_handshake_response; ++struct message_data; ++struct message_handshake_cookie; ++ ++void noise_init(void); ++void noise_handshake_init(struct noise_handshake *handshake, struct noise_static_identity *static_identity, const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN], struct wireguard_peer *peer); ++void noise_handshake_clear(struct noise_handshake *handshake); ++void noise_keypair_put(struct noise_keypair *keypair); ++struct noise_keypair *noise_keypair_get(struct noise_keypair *keypair); ++void noise_keypairs_clear(struct noise_keypairs *keypairs); ++bool noise_received_with_keypair(struct noise_keypairs *keypairs, struct noise_keypair *received_keypair); ++ ++void noise_set_static_identity_private_key(struct noise_static_identity *static_identity, const u8 private_key[NOISE_PUBLIC_KEY_LEN]); ++void noise_set_static_identity_preshared_key(struct noise_static_identity *static_identity, const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]); ++ ++bool noise_handshake_create_initiation(struct message_handshake_initiation *dst, struct noise_handshake *handshake); ++struct wireguard_peer *noise_handshake_consume_initiation(struct message_handshake_initiation *src, struct wireguard_device *wg); ++ ++bool noise_handshake_create_response(struct message_handshake_response *dst, struct noise_handshake *peer); ++struct wireguard_peer *noise_handshake_consume_response(struct message_handshake_response *src, struct wireguard_device *wg); ++ ++bool noise_handshake_begin_session(struct noise_handshake *handshake, struct noise_keypairs *keypairs, bool i_am_the_initiator); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/packets.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,44 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef PACKETS_H ++#define PACKETS_H ++ ++#include "noise.h" ++#include "messages.h" ++#include "socket.h" ++ ++#include ++#include ++ ++struct wireguard_device; ++struct wireguard_peer; ++struct sk_buff; ++ ++/* receive.c */ ++void packet_receive(struct wireguard_device *wg, struct sk_buff *skb); ++void packet_process_queued_handshake_packets(struct work_struct *work); ++ ++/* send.c */ ++void packet_send_queue(struct wireguard_peer *peer); ++void packet_send_keepalive(struct wireguard_peer *peer); ++void packet_queue_handshake_initiation(struct wireguard_peer *peer); ++void packet_send_queued_handshakes(struct work_struct *work); ++void packet_send_handshake_response(struct wireguard_peer *peer); ++void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *initiating_skb, void *data, size_t data_len, __le32 sender_index); ++ ++/* data.c */ ++typedef void (*packet_create_data_callback_t)(struct sk_buff_head *, struct wireguard_peer *); ++typedef void (*packet_consume_data_callback_t)(struct sk_buff *skb, struct wireguard_peer *, struct endpoint *, bool used_new_key, int err); ++int packet_create_data(struct sk_buff_head *queue, struct wireguard_peer *peer, packet_create_data_callback_t callback); ++void packet_consume_data(struct sk_buff *skb, size_t offset, struct wireguard_device *wg, packet_consume_data_callback_t callback); ++ ++#ifdef CONFIG_WIREGUARD_PARALLEL ++int packet_init_data_caches(void); ++void packet_deinit_data_caches(void); ++#endif ++ ++#ifdef DEBUG ++bool packet_counter_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/peer.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,75 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef PEER_H ++#define PEER_H ++ ++#include "noise.h" ++#include "cookie.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct wireguard_device; ++ ++struct endpoint { ++ union { ++ struct sockaddr addr; ++ struct sockaddr_in addr4; ++ struct sockaddr_in6 addr6; ++ }; ++ union { ++ struct in_addr src4; ++ struct in6_addr src6; ++ }; ++}; ++ ++struct wireguard_peer { ++ struct wireguard_device *device; ++ struct endpoint endpoint; ++ struct dst_cache endpoint_cache; ++ rwlock_t endpoint_lock; ++ struct noise_handshake handshake; ++ struct noise_keypairs keypairs; ++ u64 last_sent_handshake; ++ struct work_struct transmit_handshake_work, clear_peer_work; ++ struct cookie latest_cookie; ++ struct hlist_node pubkey_hash; ++ u64 rx_bytes, tx_bytes; ++ struct timer_list timer_retransmit_handshake, timer_send_keepalive, timer_new_handshake, timer_kill_ephemerals, timer_persistent_keepalive; ++ unsigned int timer_handshake_attempts; ++ unsigned long persistent_keepalive_interval; ++ bool timers_enabled; ++ bool timer_need_another_keepalive; ++ bool need_resend_queue; ++ bool sent_lastminute_handshake; ++ struct timeval walltime_last_handshake; ++ struct sk_buff_head tx_packet_queue; ++ struct kref refcount; ++ struct rcu_head rcu; ++ struct list_head peer_list; ++ u64 internal_id; ++#ifdef CONFIG_WIREGUARD_PARALLEL ++ atomic_t parallel_encryption_inflight; ++#endif ++}; ++ ++struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN]); ++ ++struct wireguard_peer *peer_get(struct wireguard_peer *peer); ++struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer); ++ ++void peer_put(struct wireguard_peer *peer); ++void peer_remove(struct wireguard_peer *peer); ++void peer_remove_all(struct wireguard_device *wg); ++ ++struct wireguard_peer *peer_lookup_by_index(struct wireguard_device *wg, u32 index); ++ ++int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data); ++int peer_for_each(struct wireguard_device *wg, int (*fn)(struct wireguard_peer *peer, void *ctx), void *data); ++ ++unsigned int peer_total_count(struct wireguard_device *wg); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/ratelimiter.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,26 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef RATELIMITER_H ++#define RATELIMITER_H ++ ++#include ++ ++struct wireguard_device; ++struct sk_buff; ++ ++struct ratelimiter { ++ struct net *net; ++ struct xt_hashlimit_mtinfo1 v4_info; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct xt_hashlimit_mtinfo1 v6_info; ++#endif ++}; ++ ++int ratelimiter_init(struct ratelimiter *ratelimiter, struct wireguard_device *wg); ++void ratelimiter_uninit(struct ratelimiter *ratelimiter); ++bool ratelimiter_allow(struct ratelimiter *ratelimiter, struct sk_buff *skb); ++ ++int ratelimiter_module_init(void); ++void ratelimiter_module_deinit(void); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/routingtable.h 2017-03-05 17:03:41.527682414 +0200 +@@ -0,0 +1,40 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef ROUTINGTABLE_H ++#define ROUTINGTABLE_H ++ ++#include ++#include ++#include ++ ++struct wireguard_peer; ++struct routing_table_node; ++ ++struct routing_table { ++ struct routing_table_node __rcu *root4; ++ struct routing_table_node __rcu *root6; ++ struct mutex table_update_lock; ++}; ++ ++void routing_table_init(struct routing_table *table); ++void routing_table_free(struct routing_table *table); ++int routing_table_insert_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer); ++int routing_table_insert_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr, struct wireguard_peer *peer); ++int routing_table_remove_v4(struct routing_table *table, const struct in_addr *ip, u8 cidr); ++int routing_table_remove_v6(struct routing_table *table, const struct in6_addr *ip, u8 cidr); ++int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_peer *peer); ++int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family)); ++int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)); ++int routing_table_walk_ips_by_peer_sleepable(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family)); ++ ++/* These return a strong reference to a peer: */ ++struct wireguard_peer *routing_table_lookup_v4(struct routing_table *table, const struct in_addr *ip); ++struct wireguard_peer *routing_table_lookup_v6(struct routing_table *table, const struct in6_addr *ip); ++struct wireguard_peer *routing_table_lookup_dst(struct routing_table *table, struct sk_buff *skb); ++struct wireguard_peer *routing_table_lookup_src(struct routing_table *table, struct sk_buff *skb); ++ ++#ifdef DEBUG ++bool routing_table_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/socket.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,24 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGSOCKET_H ++#define WGSOCKET_H ++ ++#include ++#include ++#include ++#include ++ ++struct wireguard_device; ++struct endpoint; ++ ++int socket_init(struct wireguard_device *wg); ++void socket_uninit(struct wireguard_device *wg); ++int socket_send_buffer_to_peer(struct wireguard_peer *peer, void *data, size_t len, u8 ds); ++int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8 ds); ++int socket_send_buffer_as_reply_to_skb(struct wireguard_device *wg, struct sk_buff *in_skb, void *out_buffer, size_t len); ++ ++int socket_endpoint_from_skb(struct endpoint *endpoint, struct sk_buff *skb); ++void socket_set_peer_endpoint(struct wireguard_peer *peer, struct endpoint *endpoint); ++void socket_clear_peer_endpoint_src(struct wireguard_peer *peer); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/timers.h 2017-03-05 17:03:41.529682426 +0200 +@@ -0,0 +1,19 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef WGTIMERS_H ++#define WGTIMERS_H ++ ++struct wireguard_peer; ++ ++void timers_init_peer(struct wireguard_peer *peer); ++void timers_uninit_peer(struct wireguard_peer *peer); ++ ++void timers_data_sent(struct wireguard_peer *peer); ++void timers_data_received(struct wireguard_peer *peer); ++void timers_any_authenticated_packet_received(struct wireguard_peer *peer); ++void timers_handshake_initiated(struct wireguard_peer *peer); ++void timers_handshake_complete(struct wireguard_peer *peer); ++void timers_ephemeral_key_created(struct wireguard_peer *peer); ++void timers_any_authenticated_packet_traversal(struct wireguard_peer *peer); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/uapi.h 2017-03-05 17:03:41.530682431 +0200 +@@ -0,0 +1,159 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * Userspace API for WireGuard ++ * --------------------------- ++ * ++ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: NULL }): ++ * ++ * Returns the number of bytes required to hold the peers of a device (`ret_peers_size`). ++ * ++ * ioctl(WG_GET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }): ++ * ++ * Retrevies device info, peer info, and ipmask info. ++ * ++ * `user_pointer` must point to a region of memory of size `sizeof(struct wgdevice) + ret_peers_size` ++ * and containing the structure `struct wgdevice { .peers_size: ret_peers_size }`. ++ * ++ * Writes to `user_pointer` a succession of structs: ++ * ++ * struct wgdevice { .num_peers = 3 } ++ * struct wgpeer { .num_ipmasks = 4 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 2 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 0 } ++ * ++ * Returns 0 on success. Returns -EMSGSIZE if there is too much data for the size of passed-in ++ * memory, in which case, this should be recalculated using the call above. Returns -errno if ++ * another error occured. ++ * ++ * ioctl(WG_SET_DEVICE, { .ifr_name: "wg0", .ifr_data: user_pointer }): ++ * ++ * Sets device info, peer info, and ipmask info. ++ * ++ * `user_pointer` must point to a region of memory containing a succession of structs: ++ * ++ * struct wgdevice { .num_peers = 3 } ++ * struct wgpeer { .num_ipmasks = 4 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 2 } ++ * struct wgipmask ++ * struct wgipmask ++ * struct wgpeer { .num_ipmasks = 0 } ++ * ++ * If `wgdevice->flags & WGDEVICE_REPLACE_PEERS` is true, removes all peers of device before adding new ones. ++ * If `wgpeer->flags & WGPEER_REMOVE_ME` is true, the peer identified by `wgpeer->public_key` is removed. ++ * If `wgpeer->flags & WGPEER_REPLACE_IPMASKS` is true, removes all ipmasks before adding new ones. ++ * If `wgdevice->private_key` is filled with zeros, no action is taken on the private key. ++ * If `wgdevice->preshared_key` is filled with zeros, no action is taken on the pre-shared key. ++ * If `wgdevice->flags & WGDEVICE_REMOVE_PRIVATE_KEY` is true, the private key is removed. ++ * If `wgdevice->flags & WGDEVICE_REMOVE_PRESHARED_KEY` is true, the pre-shared key is removed. ++ * ++ * Returns 0 on success, or -errno if an error occurred. ++ */ ++ ++ ++#ifndef WGUAPI_H ++#define WGUAPI_H ++ ++#ifdef __linux__ ++#include ++#else ++#include ++typedef uint8_t __u8; ++typedef uint16_t __u16; ++typedef uint32_t __u32; ++typedef uint64_t __u64; ++typedef int32_t __s32; ++#endif ++#ifdef __KERNEL__ ++#include ++#include ++#else ++#include ++#include ++#include ++#include ++#endif ++ ++#define WG_GET_DEVICE (SIOCDEVPRIVATE + 0) ++#define WG_SET_DEVICE (SIOCDEVPRIVATE + 1) ++ ++#define WG_KEY_LEN 32 ++ ++struct wgipmask { ++ __s32 family; ++ union { ++ struct in_addr ip4; ++ struct in6_addr ip6; ++ }; ++ __u8 cidr; ++}; ++ ++enum { ++ WGPEER_REMOVE_ME = (1 << 0), ++ WGPEER_REPLACE_IPMASKS = (1 << 1) ++}; ++struct wgpeer { ++ __u8 public_key[WG_KEY_LEN]; /* Get/Set */ ++ __u32 flags; /* Set */ ++ ++ union { ++ struct sockaddr addr; ++ struct sockaddr_in addr4; ++ struct sockaddr_in6 addr6; ++ } endpoint; /* Get/Set */ ++ ++ struct timeval last_handshake_time; /* Get */ ++ __u64 rx_bytes, tx_bytes; /* Get */ ++ __u16 persistent_keepalive_interval; /* Get/Set -- 0 = off, 0xffff = unset */ ++ ++ __u16 num_ipmasks; /* Get/Set */ ++}; ++ ++enum { ++ WGDEVICE_REPLACE_PEERS = (1 << 0), ++ WGDEVICE_REMOVE_PRIVATE_KEY = (1 << 1), ++ WGDEVICE_REMOVE_PRESHARED_KEY = (1 << 2), ++ WGDEVICE_REMOVE_FWMARK = (1 << 3) ++}; ++struct wgdevice { ++ char interface[IFNAMSIZ]; /* Get */ ++ __u32 flags; /* Set */ ++ ++ __u8 public_key[WG_KEY_LEN]; /* Get */ ++ __u8 private_key[WG_KEY_LEN]; /* Get/Set */ ++ __u8 preshared_key[WG_KEY_LEN]; /* Get/Set */ ++ __u32 fwmark; /* Get/Set */ ++ __u16 port; /* Get/Set */ ++ ++ union { ++ __u16 num_peers; /* Get/Set */ ++ __u32 peers_size; /* Get */ ++ }; ++}; ++ ++/* These are simply for convenience in iterating. It allows you to write something like: ++ * ++ * for_each_wgpeer(device, peer, i) { ++ * for_each_wgipmask(peer, ipmask, j) { ++ * do_something_with_ipmask(ipmask); ++ * } ++ * } ++ */ ++#define for_each_wgpeer(__dev, __peer, __i) for ((__i) = 0, (__peer) = (struct wgpeer *)((uint8_t *)(__dev) + sizeof(struct wgdevice)); \ ++ (__i) < (__dev)->num_peers; \ ++ ++(__i), (__peer) = (struct wgpeer *)((uint8_t *)(__peer) + sizeof(struct wgpeer) + (sizeof(struct wgipmask) * (__peer)->num_ipmasks))) ++ ++#define for_each_wgipmask(__peer, __ipmask, __i) for ((__i) = 0, (__ipmask) = (struct wgipmask *)((uint8_t *)(__peer) + sizeof(struct wgpeer)); \ ++ (__i) < (__peer)->num_ipmasks; \ ++ ++(__i), (__ipmask) = (struct wgipmask *)((uint8_t *)(__ipmask) + sizeof(struct wgipmask))) ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/version.h 2017-03-05 17:03:41.530682431 +0200 +@@ -0,0 +1 @@ ++#define WIREGUARD_VERSION "0.0.20170223" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/blake2s.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,556 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++static const u8 blake2s_testvecs[][BLAKE2S_OUTBYTES] = { ++ { 0x69, 0x21, 0x7A, 0x30, 0x79, 0x90, 0x80, 0x94, 0xE1, 0x11, 0x21, 0xD0, 0x42, 0x35, 0x4A, 0x7C, 0x1F, 0x55, 0xB6, 0x48, 0x2C, 0xA1, 0xA5, 0x1E, 0x1B, 0x25, 0x0D, 0xFD, 0x1E, 0xD0, 0xEE, 0xF9 }, ++ { 0xE3, 0x4D, 0x74, 0xDB, 0xAF, 0x4F, 0xF4, 0xC6, 0xAB, 0xD8, 0x71, 0xCC, 0x22, 0x04, 0x51, 0xD2, 0xEA, 0x26, 0x48, 0x84, 0x6C, 0x77, 0x57, 0xFB, 0xAA, 0xC8, 0x2F, 0xE5, 0x1A, 0xD6, 0x4B, 0xEA }, ++ { 0xDD, 0xAD, 0x9A, 0xB1, 0x5D, 0xAC, 0x45, 0x49, 0xBA, 0x42, 0xF4, 0x9D, 0x26, 0x24, 0x96, 0xBE, 0xF6, 0xC0, 0xBA, 0xE1, 0xDD, 0x34, 0x2A, 0x88, 0x08, 0xF8, 0xEA, 0x26, 0x7C, 0x6E, 0x21, 0x0C }, ++ { 0xE8, 0xF9, 0x1C, 0x6E, 0xF2, 0x32, 0xA0, 0x41, 0x45, 0x2A, 0xB0, 0xE1, 0x49, 0x07, 0x0C, 0xDD, 0x7D, 0xD1, 0x76, 0x9E, 0x75, 0xB3, 0xA5, 0x92, 0x1B, 0xE3, 0x78, 0x76, 0xC4, 0x5C, 0x99, 0x00 }, ++ { 0x0C, 0xC7, 0x0E, 0x00, 0x34, 0x8B, 0x86, 0xBA, 0x29, 0x44, 0xD0, 0xC3, 0x20, 0x38, 0xB2, 0x5C, 0x55, 0x58, 0x4F, 0x90, 0xDF, 0x23, 0x04, 0xF5, 0x5F, 0xA3, 0x32, 0xAF, 0x5F, 0xB0, 0x1E, 0x20 }, ++ { 0xEC, 0x19, 0x64, 0x19, 0x10, 0x87, 0xA4, 0xFE, 0x9D, 0xF1, 0xC7, 0x95, 0x34, 0x2A, 0x02, 0xFF, 0xC1, 0x91, 0xA5, 0xB2, 0x51, 0x76, 0x48, 0x56, 0xAE, 0x5B, 0x8B, 0x57, 0x69, 0xF0, 0xC6, 0xCD }, ++ { 0xE1, 0xFA, 0x51, 0x61, 0x8D, 0x7D, 0xF4, 0xEB, 0x70, 0xCF, 0x0D, 0x5A, 0x9E, 0x90, 0x6F, 0x80, 0x6E, 0x9D, 0x19, 0xF7, 0xF4, 0xF0, 0x1E, 0x3B, 0x62, 0x12, 0x88, 0xE4, 0x12, 0x04, 0x05, 0xD6 }, ++ { 0x59, 0x80, 0x01, 0xFA, 0xFB, 0xE8, 0xF9, 0x4E, 0xC6, 0x6D, 0xC8, 0x27, 0xD0, 0x12, 0xCF, 0xCB, 0xBA, 0x22, 0x28, 0x56, 0x9F, 0x44, 0x8E, 0x89, 0xEA, 0x22, 0x08, 0xC8, 0xBF, 0x76, 0x92, 0x93 }, ++ { 0xC7, 0xE8, 0x87, 0xB5, 0x46, 0x62, 0x36, 0x35, 0xE9, 0x3E, 0x04, 0x95, 0x59, 0x8F, 0x17, 0x26, 0x82, 0x19, 0x96, 0xC2, 0x37, 0x77, 0x05, 0xB9, 0x3A, 0x1F, 0x63, 0x6F, 0x87, 0x2B, 0xFA, 0x2D }, ++ { 0xC3, 0x15, 0xA4, 0x37, 0xDD, 0x28, 0x06, 0x2A, 0x77, 0x0D, 0x48, 0x19, 0x67, 0x13, 0x6B, 0x1B, 0x5E, 0xB8, 0x8B, 0x21, 0xEE, 0x53, 0xD0, 0x32, 0x9C, 0x58, 0x97, 0x12, 0x6E, 0x9D, 0xB0, 0x2C }, ++ { 0xBB, 0x47, 0x3D, 0xED, 0xDC, 0x05, 0x5F, 0xEA, 0x62, 0x28, 0xF2, 0x07, 0xDA, 0x57, 0x53, 0x47, 0xBB, 0x00, 0x40, 0x4C, 0xD3, 0x49, 0xD3, 0x8C, 0x18, 0x02, 0x63, 0x07, 0xA2, 0x24, 0xCB, 0xFF }, ++ { 0x68, 0x7E, 0x18, 0x73, 0xA8, 0x27, 0x75, 0x91, 0xBB, 0x33, 0xD9, 0xAD, 0xF9, 0xA1, 0x39, 0x12, 0xEF, 0xEF, 0xE5, 0x57, 0xCA, 0xFC, 0x39, 0xA7, 0x95, 0x26, 0x23, 0xE4, 0x72, 0x55, 0xF1, 0x6D }, ++ { 0x1A, 0xC7, 0xBA, 0x75, 0x4D, 0x6E, 0x2F, 0x94, 0xE0, 0xE8, 0x6C, 0x46, 0xBF, 0xB2, 0x62, 0xAB, 0xBB, 0x74, 0xF4, 0x50, 0xEF, 0x45, 0x6D, 0x6B, 0x4D, 0x97, 0xAA, 0x80, 0xCE, 0x6D, 0xA7, 0x67 }, ++ { 0x01, 0x2C, 0x97, 0x80, 0x96, 0x14, 0x81, 0x6B, 0x5D, 0x94, 0x94, 0x47, 0x7D, 0x4B, 0x68, 0x7D, 0x15, 0xB9, 0x6E, 0xB6, 0x9C, 0x0E, 0x80, 0x74, 0xA8, 0x51, 0x6F, 0x31, 0x22, 0x4B, 0x5C, 0x98 }, ++ { 0x91, 0xFF, 0xD2, 0x6C, 0xFA, 0x4D, 0xA5, 0x13, 0x4C, 0x7E, 0xA2, 0x62, 0xF7, 0x88, 0x9C, 0x32, 0x9F, 0x61, 0xF6, 0xA6, 0x57, 0x22, 0x5C, 0xC2, 0x12, 0xF4, 0x00, 0x56, 0xD9, 0x86, 0xB3, 0xF4 }, ++ { 0xD9, 0x7C, 0x82, 0x8D, 0x81, 0x82, 0xA7, 0x21, 0x80, 0xA0, 0x6A, 0x78, 0x26, 0x83, 0x30, 0x67, 0x3F, 0x7C, 0x4E, 0x06, 0x35, 0x94, 0x7C, 0x04, 0xC0, 0x23, 0x23, 0xFD, 0x45, 0xC0, 0xA5, 0x2D }, ++ { 0xEF, 0xC0, 0x4C, 0xDC, 0x39, 0x1C, 0x7E, 0x91, 0x19, 0xBD, 0x38, 0x66, 0x8A, 0x53, 0x4E, 0x65, 0xFE, 0x31, 0x03, 0x6D, 0x6A, 0x62, 0x11, 0x2E, 0x44, 0xEB, 0xEB, 0x11, 0xF9, 0xC5, 0x70, 0x80 }, ++ { 0x99, 0x2C, 0xF5, 0xC0, 0x53, 0x44, 0x2A, 0x5F, 0xBC, 0x4F, 0xAF, 0x58, 0x3E, 0x04, 0xE5, 0x0B, 0xB7, 0x0D, 0x2F, 0x39, 0xFB, 0xB6, 0xA5, 0x03, 0xF8, 0x9E, 0x56, 0xA6, 0x3E, 0x18, 0x57, 0x8A }, ++ { 0x38, 0x64, 0x0E, 0x9F, 0x21, 0x98, 0x3E, 0x67, 0xB5, 0x39, 0xCA, 0xCC, 0xAE, 0x5E, 0xCF, 0x61, 0x5A, 0xE2, 0x76, 0x4F, 0x75, 0xA0, 0x9C, 0x9C, 0x59, 0xB7, 0x64, 0x83, 0xC1, 0xFB, 0xC7, 0x35 }, ++ { 0x21, 0x3D, 0xD3, 0x4C, 0x7E, 0xFE, 0x4F, 0xB2, 0x7A, 0x6B, 0x35, 0xF6, 0xB4, 0x00, 0x0D, 0x1F, 0xE0, 0x32, 0x81, 0xAF, 0x3C, 0x72, 0x3E, 0x5C, 0x9F, 0x94, 0x74, 0x7A, 0x5F, 0x31, 0xCD, 0x3B }, ++ { 0xEC, 0x24, 0x6E, 0xEE, 0xB9, 0xCE, 0xD3, 0xF7, 0xAD, 0x33, 0xED, 0x28, 0x66, 0x0D, 0xD9, 0xBB, 0x07, 0x32, 0x51, 0x3D, 0xB4, 0xE2, 0xFA, 0x27, 0x8B, 0x60, 0xCD, 0xE3, 0x68, 0x2A, 0x4C, 0xCD }, ++ { 0xAC, 0x9B, 0x61, 0xD4, 0x46, 0x64, 0x8C, 0x30, 0x05, 0xD7, 0x89, 0x2B, 0xF3, 0xA8, 0x71, 0x9F, 0x4C, 0x81, 0x81, 0xCF, 0xDC, 0xBC, 0x2B, 0x79, 0xFE, 0xF1, 0x0A, 0x27, 0x9B, 0x91, 0x10, 0x95 }, ++ { 0x7B, 0xF8, 0xB2, 0x29, 0x59, 0xE3, 0x4E, 0x3A, 0x43, 0xF7, 0x07, 0x92, 0x23, 0xE8, 0x3A, 0x97, 0x54, 0x61, 0x7D, 0x39, 0x1E, 0x21, 0x3D, 0xFD, 0x80, 0x8E, 0x41, 0xB9, 0xBE, 0xAD, 0x4C, 0xE7 }, ++ { 0x68, 0xD4, 0xB5, 0xD4, 0xFA, 0x0E, 0x30, 0x2B, 0x64, 0xCC, 0xC5, 0xAF, 0x79, 0x29, 0x13, 0xAC, 0x4C, 0x88, 0xEC, 0x95, 0xC0, 0x7D, 0xDF, 0x40, 0x69, 0x42, 0x56, 0xEB, 0x88, 0xCE, 0x9F, 0x3D }, ++ { 0xB2, 0xC2, 0x42, 0x0F, 0x05, 0xF9, 0xAB, 0xE3, 0x63, 0x15, 0x91, 0x93, 0x36, 0xB3, 0x7E, 0x4E, 0x0F, 0xA3, 0x3F, 0xF7, 0xE7, 0x6A, 0x49, 0x27, 0x67, 0x00, 0x6F, 0xDB, 0x5D, 0x93, 0x54, 0x62 }, ++ { 0x13, 0x4F, 0x61, 0xBB, 0xD0, 0xBB, 0xB6, 0x9A, 0xED, 0x53, 0x43, 0x90, 0x45, 0x51, 0xA3, 0xE6, 0xC1, 0xAA, 0x7D, 0xCD, 0xD7, 0x7E, 0x90, 0x3E, 0x70, 0x23, 0xEB, 0x7C, 0x60, 0x32, 0x0A, 0xA7 }, ++ { 0x46, 0x93, 0xF9, 0xBF, 0xF7, 0xD4, 0xF3, 0x98, 0x6A, 0x7D, 0x17, 0x6E, 0x6E, 0x06, 0xF7, 0x2A, 0xD1, 0x49, 0x0D, 0x80, 0x5C, 0x99, 0xE2, 0x53, 0x47, 0xB8, 0xDE, 0x77, 0xB4, 0xDB, 0x6D, 0x9B }, ++ { 0x85, 0x3E, 0x26, 0xF7, 0x41, 0x95, 0x3B, 0x0F, 0xD5, 0xBD, 0xB4, 0x24, 0xE8, 0xAB, 0x9E, 0x8B, 0x37, 0x50, 0xEA, 0xA8, 0xEF, 0x61, 0xE4, 0x79, 0x02, 0xC9, 0x1E, 0x55, 0x4E, 0x9C, 0x73, 0xB9 }, ++ { 0xF7, 0xDE, 0x53, 0x63, 0x61, 0xAB, 0xAA, 0x0E, 0x15, 0x81, 0x56, 0xCF, 0x0E, 0xA4, 0xF6, 0x3A, 0x99, 0xB5, 0xE4, 0x05, 0x4F, 0x8F, 0xA4, 0xC9, 0xD4, 0x5F, 0x62, 0x85, 0xCA, 0xD5, 0x56, 0x94 }, ++ { 0x4C, 0x23, 0x06, 0x08, 0x86, 0x0A, 0x99, 0xAE, 0x8D, 0x7B, 0xD5, 0xC2, 0xCC, 0x17, 0xFA, 0x52, 0x09, 0x6B, 0x9A, 0x61, 0xBE, 0xDB, 0x17, 0xCB, 0x76, 0x17, 0x86, 0x4A, 0xD2, 0x9C, 0xA7, 0xA6 }, ++ { 0xAE, 0xB9, 0x20, 0xEA, 0x87, 0x95, 0x2D, 0xAD, 0xB1, 0xFB, 0x75, 0x92, 0x91, 0xE3, 0x38, 0x81, 0x39, 0xA8, 0x72, 0x86, 0x50, 0x01, 0x88, 0x6E, 0xD8, 0x47, 0x52, 0xE9, 0x3C, 0x25, 0x0C, 0x2A }, ++ { 0xAB, 0xA4, 0xAD, 0x9B, 0x48, 0x0B, 0x9D, 0xF3, 0xD0, 0x8C, 0xA5, 0xE8, 0x7B, 0x0C, 0x24, 0x40, 0xD4, 0xE4, 0xEA, 0x21, 0x22, 0x4C, 0x2E, 0xB4, 0x2C, 0xBA, 0xE4, 0x69, 0xD0, 0x89, 0xB9, 0x31 }, ++ { 0x05, 0x82, 0x56, 0x07, 0xD7, 0xFD, 0xF2, 0xD8, 0x2E, 0xF4, 0xC3, 0xC8, 0xC2, 0xAE, 0xA9, 0x61, 0xAD, 0x98, 0xD6, 0x0E, 0xDF, 0xF7, 0xD0, 0x18, 0x98, 0x3E, 0x21, 0x20, 0x4C, 0x0D, 0x93, 0xD1 }, ++ { 0xA7, 0x42, 0xF8, 0xB6, 0xAF, 0x82, 0xD8, 0xA6, 0xCA, 0x23, 0x57, 0xC5, 0xF1, 0xCF, 0x91, 0xDE, 0xFB, 0xD0, 0x66, 0x26, 0x7D, 0x75, 0xC0, 0x48, 0xB3, 0x52, 0x36, 0x65, 0x85, 0x02, 0x59, 0x62 }, ++ { 0x2B, 0xCA, 0xC8, 0x95, 0x99, 0x00, 0x0B, 0x42, 0xC9, 0x5A, 0xE2, 0x38, 0x35, 0xA7, 0x13, 0x70, 0x4E, 0xD7, 0x97, 0x89, 0xC8, 0x4F, 0xEF, 0x14, 0x9A, 0x87, 0x4F, 0xF7, 0x33, 0xF0, 0x17, 0xA2 }, ++ { 0xAC, 0x1E, 0xD0, 0x7D, 0x04, 0x8F, 0x10, 0x5A, 0x9E, 0x5B, 0x7A, 0xB8, 0x5B, 0x09, 0xA4, 0x92, 0xD5, 0xBA, 0xFF, 0x14, 0xB8, 0xBF, 0xB0, 0xE9, 0xFD, 0x78, 0x94, 0x86, 0xEE, 0xA2, 0xB9, 0x74 }, ++ { 0xE4, 0x8D, 0x0E, 0xCF, 0xAF, 0x49, 0x7D, 0x5B, 0x27, 0xC2, 0x5D, 0x99, 0xE1, 0x56, 0xCB, 0x05, 0x79, 0xD4, 0x40, 0xD6, 0xE3, 0x1F, 0xB6, 0x24, 0x73, 0x69, 0x6D, 0xBF, 0x95, 0xE0, 0x10, 0xE4 }, ++ { 0x12, 0xA9, 0x1F, 0xAD, 0xF8, 0xB2, 0x16, 0x44, 0xFD, 0x0F, 0x93, 0x4F, 0x3C, 0x4A, 0x8F, 0x62, 0xBA, 0x86, 0x2F, 0xFD, 0x20, 0xE8, 0xE9, 0x61, 0x15, 0x4C, 0x15, 0xC1, 0x38, 0x84, 0xED, 0x3D }, ++ { 0x7C, 0xBE, 0xE9, 0x6E, 0x13, 0x98, 0x97, 0xDC, 0x98, 0xFB, 0xEF, 0x3B, 0xE8, 0x1A, 0xD4, 0xD9, 0x64, 0xD2, 0x35, 0xCB, 0x12, 0x14, 0x1F, 0xB6, 0x67, 0x27, 0xE6, 0xE5, 0xDF, 0x73, 0xA8, 0x78 }, ++ { 0xEB, 0xF6, 0x6A, 0xBB, 0x59, 0x7A, 0xE5, 0x72, 0xA7, 0x29, 0x7C, 0xB0, 0x87, 0x1E, 0x35, 0x5A, 0xCC, 0xAF, 0xAD, 0x83, 0x77, 0xB8, 0xE7, 0x8B, 0xF1, 0x64, 0xCE, 0x2A, 0x18, 0xDE, 0x4B, 0xAF }, ++ { 0x71, 0xB9, 0x33, 0xB0, 0x7E, 0x4F, 0xF7, 0x81, 0x8C, 0xE0, 0x59, 0xD0, 0x08, 0x82, 0x9E, 0x45, 0x3C, 0x6F, 0xF0, 0x2E, 0xC0, 0xA7, 0xDB, 0x39, 0x3F, 0xC2, 0xD8, 0x70, 0xF3, 0x7A, 0x72, 0x86 }, ++ { 0x7C, 0xF7, 0xC5, 0x13, 0x31, 0x22, 0x0B, 0x8D, 0x3E, 0xBA, 0xED, 0x9C, 0x29, 0x39, 0x8A, 0x16, 0xD9, 0x81, 0x56, 0xE2, 0x61, 0x3C, 0xB0, 0x88, 0xF2, 0xB0, 0xE0, 0x8A, 0x1B, 0xE4, 0xCF, 0x4F }, ++ { 0x3E, 0x41, 0xA1, 0x08, 0xE0, 0xF6, 0x4A, 0xD2, 0x76, 0xB9, 0x79, 0xE1, 0xCE, 0x06, 0x82, 0x79, 0xE1, 0x6F, 0x7B, 0xC7, 0xE4, 0xAA, 0x1D, 0x21, 0x1E, 0x17, 0xB8, 0x11, 0x61, 0xDF, 0x16, 0x02 }, ++ { 0x88, 0x65, 0x02, 0xA8, 0x2A, 0xB4, 0x7B, 0xA8, 0xD8, 0x67, 0x10, 0xAA, 0x9D, 0xE3, 0xD4, 0x6E, 0xA6, 0x5C, 0x47, 0xAF, 0x6E, 0xE8, 0xDE, 0x45, 0x0C, 0xCE, 0xB8, 0xB1, 0x1B, 0x04, 0x5F, 0x50 }, ++ { 0xC0, 0x21, 0xBC, 0x5F, 0x09, 0x54, 0xFE, 0xE9, 0x4F, 0x46, 0xEA, 0x09, 0x48, 0x7E, 0x10, 0xA8, 0x48, 0x40, 0xD0, 0x2F, 0x64, 0x81, 0x0B, 0xC0, 0x8D, 0x9E, 0x55, 0x1F, 0x7D, 0x41, 0x68, 0x14 }, ++ { 0x20, 0x30, 0x51, 0x6E, 0x8A, 0x5F, 0xE1, 0x9A, 0xE7, 0x9C, 0x33, 0x6F, 0xCE, 0x26, 0x38, 0x2A, 0x74, 0x9D, 0x3F, 0xD0, 0xEC, 0x91, 0xE5, 0x37, 0xD4, 0xBD, 0x23, 0x58, 0xC1, 0x2D, 0xFB, 0x22 }, ++ { 0x55, 0x66, 0x98, 0xDA, 0xC8, 0x31, 0x7F, 0xD3, 0x6D, 0xFB, 0xDF, 0x25, 0xA7, 0x9C, 0xB1, 0x12, 0xD5, 0x42, 0x58, 0x60, 0x60, 0x5C, 0xBA, 0xF5, 0x07, 0xF2, 0x3B, 0xF7, 0xE9, 0xF4, 0x2A, 0xFE }, ++ { 0x2F, 0x86, 0x7B, 0xA6, 0x77, 0x73, 0xFD, 0xC3, 0xE9, 0x2F, 0xCE, 0xD9, 0x9A, 0x64, 0x09, 0xAD, 0x39, 0xD0, 0xB8, 0x80, 0xFD, 0xE8, 0xF1, 0x09, 0xA8, 0x17, 0x30, 0xC4, 0x45, 0x1D, 0x01, 0x78 }, ++ { 0x17, 0x2E, 0xC2, 0x18, 0xF1, 0x19, 0xDF, 0xAE, 0x98, 0x89, 0x6D, 0xFF, 0x29, 0xDD, 0x98, 0x76, 0xC9, 0x4A, 0xF8, 0x74, 0x17, 0xF9, 0xAE, 0x4C, 0x70, 0x14, 0xBB, 0x4E, 0x4B, 0x96, 0xAF, 0xC7 }, ++ { 0x3F, 0x85, 0x81, 0x4A, 0x18, 0x19, 0x5F, 0x87, 0x9A, 0xA9, 0x62, 0xF9, 0x5D, 0x26, 0xBD, 0x82, 0xA2, 0x78, 0xF2, 0xB8, 0x23, 0x20, 0x21, 0x8F, 0x6B, 0x3B, 0xD6, 0xF7, 0xF6, 0x67, 0xA6, 0xD9 }, ++ { 0x1B, 0x61, 0x8F, 0xBA, 0xA5, 0x66, 0xB3, 0xD4, 0x98, 0xC1, 0x2E, 0x98, 0x2C, 0x9E, 0xC5, 0x2E, 0x4D, 0xA8, 0x5A, 0x8C, 0x54, 0xF3, 0x8F, 0x34, 0xC0, 0x90, 0x39, 0x4F, 0x23, 0xC1, 0x84, 0xC1 }, ++ { 0x0C, 0x75, 0x8F, 0xB5, 0x69, 0x2F, 0xFD, 0x41, 0xA3, 0x57, 0x5D, 0x0A, 0xF0, 0x0C, 0xC7, 0xFB, 0xF2, 0xCB, 0xE5, 0x90, 0x5A, 0x58, 0x32, 0x3A, 0x88, 0xAE, 0x42, 0x44, 0xF6, 0xE4, 0xC9, 0x93 }, ++ { 0xA9, 0x31, 0x36, 0x0C, 0xAD, 0x62, 0x8C, 0x7F, 0x12, 0xA6, 0xC1, 0xC4, 0xB7, 0x53, 0xB0, 0xF4, 0x06, 0x2A, 0xEF, 0x3C, 0xE6, 0x5A, 0x1A, 0xE3, 0xF1, 0x93, 0x69, 0xDA, 0xDF, 0x3A, 0xE2, 0x3D }, ++ { 0xCB, 0xAC, 0x7D, 0x77, 0x3B, 0x1E, 0x3B, 0x3C, 0x66, 0x91, 0xD7, 0xAB, 0xB7, 0xE9, 0xDF, 0x04, 0x5C, 0x8B, 0xA1, 0x92, 0x68, 0xDE, 0xD1, 0x53, 0x20, 0x7F, 0x5E, 0x80, 0x43, 0x52, 0xEC, 0x5D }, ++ { 0x23, 0xA1, 0x96, 0xD3, 0x80, 0x2E, 0xD3, 0xC1, 0xB3, 0x84, 0x01, 0x9A, 0x82, 0x32, 0x58, 0x40, 0xD3, 0x2F, 0x71, 0x95, 0x0C, 0x45, 0x80, 0xB0, 0x34, 0x45, 0xE0, 0x89, 0x8E, 0x14, 0x05, 0x3C }, ++ { 0xF4, 0x49, 0x54, 0x70, 0xF2, 0x26, 0xC8, 0xC2, 0x14, 0xBE, 0x08, 0xFD, 0xFA, 0xD4, 0xBC, 0x4A, 0x2A, 0x9D, 0xBE, 0xA9, 0x13, 0x6A, 0x21, 0x0D, 0xF0, 0xD4, 0xB6, 0x49, 0x29, 0xE6, 0xFC, 0x14 }, ++ { 0xE2, 0x90, 0xDD, 0x27, 0x0B, 0x46, 0x7F, 0x34, 0xAB, 0x1C, 0x00, 0x2D, 0x34, 0x0F, 0xA0, 0x16, 0x25, 0x7F, 0xF1, 0x9E, 0x58, 0x33, 0xFD, 0xBB, 0xF2, 0xCB, 0x40, 0x1C, 0x3B, 0x28, 0x17, 0xDE }, ++ { 0x9F, 0xC7, 0xB5, 0xDE, 0xD3, 0xC1, 0x50, 0x42, 0xB2, 0xA6, 0x58, 0x2D, 0xC3, 0x9B, 0xE0, 0x16, 0xD2, 0x4A, 0x68, 0x2D, 0x5E, 0x61, 0xAD, 0x1E, 0xFF, 0x9C, 0x63, 0x30, 0x98, 0x48, 0xF7, 0x06 }, ++ { 0x8C, 0xCA, 0x67, 0xA3, 0x6D, 0x17, 0xD5, 0xE6, 0x34, 0x1C, 0xB5, 0x92, 0xFD, 0x7B, 0xEF, 0x99, 0x26, 0xC9, 0xE3, 0xAA, 0x10, 0x27, 0xEA, 0x11, 0xA7, 0xD8, 0xBD, 0x26, 0x0B, 0x57, 0x6E, 0x04 }, ++ { 0x40, 0x93, 0x92, 0xF5, 0x60, 0xF8, 0x68, 0x31, 0xDA, 0x43, 0x73, 0xEE, 0x5E, 0x00, 0x74, 0x26, 0x05, 0x95, 0xD7, 0xBC, 0x24, 0x18, 0x3B, 0x60, 0xED, 0x70, 0x0D, 0x45, 0x83, 0xD3, 0xF6, 0xF0 }, ++ { 0x28, 0x02, 0x16, 0x5D, 0xE0, 0x90, 0x91, 0x55, 0x46, 0xF3, 0x39, 0x8C, 0xD8, 0x49, 0x16, 0x4A, 0x19, 0xF9, 0x2A, 0xDB, 0xC3, 0x61, 0xAD, 0xC9, 0x9B, 0x0F, 0x20, 0xC8, 0xEA, 0x07, 0x10, 0x54 }, ++ { 0xAD, 0x83, 0x91, 0x68, 0xD9, 0xF8, 0xA4, 0xBE, 0x95, 0xBA, 0x9E, 0xF9, 0xA6, 0x92, 0xF0, 0x72, 0x56, 0xAE, 0x43, 0xFE, 0x6F, 0x98, 0x64, 0xE2, 0x90, 0x69, 0x1B, 0x02, 0x56, 0xCE, 0x50, 0xA9 }, ++ { 0x75, 0xFD, 0xAA, 0x50, 0x38, 0xC2, 0x84, 0xB8, 0x6D, 0x6E, 0x8A, 0xFF, 0xE8, 0xB2, 0x80, 0x7E, 0x46, 0x7B, 0x86, 0x60, 0x0E, 0x79, 0xAF, 0x36, 0x89, 0xFB, 0xC0, 0x63, 0x28, 0xCB, 0xF8, 0x94 }, ++ { 0xE5, 0x7C, 0xB7, 0x94, 0x87, 0xDD, 0x57, 0x90, 0x24, 0x32, 0xB2, 0x50, 0x73, 0x38, 0x13, 0xBD, 0x96, 0xA8, 0x4E, 0xFC, 0xE5, 0x9F, 0x65, 0x0F, 0xAC, 0x26, 0xE6, 0x69, 0x6A, 0xEF, 0xAF, 0xC3 }, ++ { 0x56, 0xF3, 0x4E, 0x8B, 0x96, 0x55, 0x7E, 0x90, 0xC1, 0xF2, 0x4B, 0x52, 0xD0, 0xC8, 0x9D, 0x51, 0x08, 0x6A, 0xCF, 0x1B, 0x00, 0xF6, 0x34, 0xCF, 0x1D, 0xDE, 0x92, 0x33, 0xB8, 0xEA, 0xAA, 0x3E }, ++ { 0x1B, 0x53, 0xEE, 0x94, 0xAA, 0xF3, 0x4E, 0x4B, 0x15, 0x9D, 0x48, 0xDE, 0x35, 0x2C, 0x7F, 0x06, 0x61, 0xD0, 0xA4, 0x0E, 0xDF, 0xF9, 0x5A, 0x0B, 0x16, 0x39, 0xB4, 0x09, 0x0E, 0x97, 0x44, 0x72 }, ++ { 0x05, 0x70, 0x5E, 0x2A, 0x81, 0x75, 0x7C, 0x14, 0xBD, 0x38, 0x3E, 0xA9, 0x8D, 0xDA, 0x54, 0x4E, 0xB1, 0x0E, 0x6B, 0xC0, 0x7B, 0xAE, 0x43, 0x5E, 0x25, 0x18, 0xDB, 0xE1, 0x33, 0x52, 0x53, 0x75 }, ++ { 0xD8, 0xB2, 0x86, 0x6E, 0x8A, 0x30, 0x9D, 0xB5, 0x3E, 0x52, 0x9E, 0xC3, 0x29, 0x11, 0xD8, 0x2F, 0x5C, 0xA1, 0x6C, 0xFF, 0x76, 0x21, 0x68, 0x91, 0xA9, 0x67, 0x6A, 0xA3, 0x1A, 0xAA, 0x6C, 0x42 }, ++ { 0xF5, 0x04, 0x1C, 0x24, 0x12, 0x70, 0xEB, 0x04, 0xC7, 0x1E, 0xC2, 0xC9, 0x5D, 0x4C, 0x38, 0xD8, 0x03, 0xB1, 0x23, 0x7B, 0x0F, 0x29, 0xFD, 0x4D, 0xB3, 0xEB, 0x39, 0x76, 0x69, 0xE8, 0x86, 0x99 }, ++ { 0x9A, 0x4C, 0xE0, 0x77, 0xC3, 0x49, 0x32, 0x2F, 0x59, 0x5E, 0x0E, 0xE7, 0x9E, 0xD0, 0xDA, 0x5F, 0xAB, 0x66, 0x75, 0x2C, 0xBF, 0xEF, 0x8F, 0x87, 0xD0, 0xE9, 0xD0, 0x72, 0x3C, 0x75, 0x30, 0xDD }, ++ { 0x65, 0x7B, 0x09, 0xF3, 0xD0, 0xF5, 0x2B, 0x5B, 0x8F, 0x2F, 0x97, 0x16, 0x3A, 0x0E, 0xDF, 0x0C, 0x04, 0xF0, 0x75, 0x40, 0x8A, 0x07, 0xBB, 0xEB, 0x3A, 0x41, 0x01, 0xA8, 0x91, 0x99, 0x0D, 0x62 }, ++ { 0x1E, 0x3F, 0x7B, 0xD5, 0xA5, 0x8F, 0xA5, 0x33, 0x34, 0x4A, 0xA8, 0xED, 0x3A, 0xC1, 0x22, 0xBB, 0x9E, 0x70, 0xD4, 0xEF, 0x50, 0xD0, 0x04, 0x53, 0x08, 0x21, 0x94, 0x8F, 0x5F, 0xE6, 0x31, 0x5A }, ++ { 0x80, 0xDC, 0xCF, 0x3F, 0xD8, 0x3D, 0xFD, 0x0D, 0x35, 0xAA, 0x28, 0x58, 0x59, 0x22, 0xAB, 0x89, 0xD5, 0x31, 0x39, 0x97, 0x67, 0x3E, 0xAF, 0x90, 0x5C, 0xEA, 0x9C, 0x0B, 0x22, 0x5C, 0x7B, 0x5F }, ++ { 0x8A, 0x0D, 0x0F, 0xBF, 0x63, 0x77, 0xD8, 0x3B, 0xB0, 0x8B, 0x51, 0x4B, 0x4B, 0x1C, 0x43, 0xAC, 0xC9, 0x5D, 0x75, 0x17, 0x14, 0xF8, 0x92, 0x56, 0x45, 0xCB, 0x6B, 0xC8, 0x56, 0xCA, 0x15, 0x0A }, ++ { 0x9F, 0xA5, 0xB4, 0x87, 0x73, 0x8A, 0xD2, 0x84, 0x4C, 0xC6, 0x34, 0x8A, 0x90, 0x19, 0x18, 0xF6, 0x59, 0xA3, 0xB8, 0x9E, 0x9C, 0x0D, 0xFE, 0xEA, 0xD3, 0x0D, 0xD9, 0x4B, 0xCF, 0x42, 0xEF, 0x8E }, ++ { 0x80, 0x83, 0x2C, 0x4A, 0x16, 0x77, 0xF5, 0xEA, 0x25, 0x60, 0xF6, 0x68, 0xE9, 0x35, 0x4D, 0xD3, 0x69, 0x97, 0xF0, 0x37, 0x28, 0xCF, 0xA5, 0x5E, 0x1B, 0x38, 0x33, 0x7C, 0x0C, 0x9E, 0xF8, 0x18 }, ++ { 0xAB, 0x37, 0xDD, 0xB6, 0x83, 0x13, 0x7E, 0x74, 0x08, 0x0D, 0x02, 0x6B, 0x59, 0x0B, 0x96, 0xAE, 0x9B, 0xB4, 0x47, 0x72, 0x2F, 0x30, 0x5A, 0x5A, 0xC5, 0x70, 0xEC, 0x1D, 0xF9, 0xB1, 0x74, 0x3C }, ++ { 0x3E, 0xE7, 0x35, 0xA6, 0x94, 0xC2, 0x55, 0x9B, 0x69, 0x3A, 0xA6, 0x86, 0x29, 0x36, 0x1E, 0x15, 0xD1, 0x22, 0x65, 0xAD, 0x6A, 0x3D, 0xED, 0xF4, 0x88, 0xB0, 0xB0, 0x0F, 0xAC, 0x97, 0x54, 0xBA }, ++ { 0xD6, 0xFC, 0xD2, 0x32, 0x19, 0xB6, 0x47, 0xE4, 0xCB, 0xD5, 0xEB, 0x2D, 0x0A, 0xD0, 0x1E, 0xC8, 0x83, 0x8A, 0x4B, 0x29, 0x01, 0xFC, 0x32, 0x5C, 0xC3, 0x70, 0x19, 0x81, 0xCA, 0x6C, 0x88, 0x8B }, ++ { 0x05, 0x20, 0xEC, 0x2F, 0x5B, 0xF7, 0xA7, 0x55, 0xDA, 0xCB, 0x50, 0xC6, 0xBF, 0x23, 0x3E, 0x35, 0x15, 0x43, 0x47, 0x63, 0xDB, 0x01, 0x39, 0xCC, 0xD9, 0xFA, 0xEF, 0xBB, 0x82, 0x07, 0x61, 0x2D }, ++ { 0xAF, 0xF3, 0xB7, 0x5F, 0x3F, 0x58, 0x12, 0x64, 0xD7, 0x66, 0x16, 0x62, 0xB9, 0x2F, 0x5A, 0xD3, 0x7C, 0x1D, 0x32, 0xBD, 0x45, 0xFF, 0x81, 0xA4, 0xED, 0x8A, 0xDC, 0x9E, 0xF3, 0x0D, 0xD9, 0x89 }, ++ { 0xD0, 0xDD, 0x65, 0x0B, 0xEF, 0xD3, 0xBA, 0x63, 0xDC, 0x25, 0x10, 0x2C, 0x62, 0x7C, 0x92, 0x1B, 0x9C, 0xBE, 0xB0, 0xB1, 0x30, 0x68, 0x69, 0x35, 0xB5, 0xC9, 0x27, 0xCB, 0x7C, 0xCD, 0x5E, 0x3B }, ++ { 0xE1, 0x14, 0x98, 0x16, 0xB1, 0x0A, 0x85, 0x14, 0xFB, 0x3E, 0x2C, 0xAB, 0x2C, 0x08, 0xBE, 0xE9, 0xF7, 0x3C, 0xE7, 0x62, 0x21, 0x70, 0x12, 0x46, 0xA5, 0x89, 0xBB, 0xB6, 0x73, 0x02, 0xD8, 0xA9 }, ++ { 0x7D, 0xA3, 0xF4, 0x41, 0xDE, 0x90, 0x54, 0x31, 0x7E, 0x72, 0xB5, 0xDB, 0xF9, 0x79, 0xDA, 0x01, 0xE6, 0xBC, 0xEE, 0xBB, 0x84, 0x78, 0xEA, 0xE6, 0xA2, 0x28, 0x49, 0xD9, 0x02, 0x92, 0x63, 0x5C }, ++ { 0x12, 0x30, 0xB1, 0xFC, 0x8A, 0x7D, 0x92, 0x15, 0xED, 0xC2, 0xD4, 0xA2, 0xDE, 0xCB, 0xDD, 0x0A, 0x6E, 0x21, 0x6C, 0x92, 0x42, 0x78, 0xC9, 0x1F, 0xC5, 0xD1, 0x0E, 0x7D, 0x60, 0x19, 0x2D, 0x94 }, ++ { 0x57, 0x50, 0xD7, 0x16, 0xB4, 0x80, 0x8F, 0x75, 0x1F, 0xEB, 0xC3, 0x88, 0x06, 0xBA, 0x17, 0x0B, 0xF6, 0xD5, 0x19, 0x9A, 0x78, 0x16, 0xBE, 0x51, 0x4E, 0x3F, 0x93, 0x2F, 0xBE, 0x0C, 0xB8, 0x71 }, ++ { 0x6F, 0xC5, 0x9B, 0x2F, 0x10, 0xFE, 0xBA, 0x95, 0x4A, 0xA6, 0x82, 0x0B, 0x3C, 0xA9, 0x87, 0xEE, 0x81, 0xD5, 0xCC, 0x1D, 0xA3, 0xC6, 0x3C, 0xE8, 0x27, 0x30, 0x1C, 0x56, 0x9D, 0xFB, 0x39, 0xCE }, ++ { 0xC7, 0xC3, 0xFE, 0x1E, 0xEB, 0xDC, 0x7B, 0x5A, 0x93, 0x93, 0x26, 0xE8, 0xDD, 0xB8, 0x3E, 0x8B, 0xF2, 0xB7, 0x80, 0xB6, 0x56, 0x78, 0xCB, 0x62, 0xF2, 0x08, 0xB0, 0x40, 0xAB, 0xDD, 0x35, 0xE2 }, ++ { 0x0C, 0x75, 0xC1, 0xA1, 0x5C, 0xF3, 0x4A, 0x31, 0x4E, 0xE4, 0x78, 0xF4, 0xA5, 0xCE, 0x0B, 0x8A, 0x6B, 0x36, 0x52, 0x8E, 0xF7, 0xA8, 0x20, 0x69, 0x6C, 0x3E, 0x42, 0x46, 0xC5, 0xA1, 0x58, 0x64 }, ++ { 0x21, 0x6D, 0xC1, 0x2A, 0x10, 0x85, 0x69, 0xA3, 0xC7, 0xCD, 0xDE, 0x4A, 0xED, 0x43, 0xA6, 0xC3, 0x30, 0x13, 0x9D, 0xDA, 0x3C, 0xCC, 0x4A, 0x10, 0x89, 0x05, 0xDB, 0x38, 0x61, 0x89, 0x90, 0x50 }, ++ { 0xA5, 0x7B, 0xE6, 0xAE, 0x67, 0x56, 0xF2, 0x8B, 0x02, 0xF5, 0x9D, 0xAD, 0xF7, 0xE0, 0xD7, 0xD8, 0x80, 0x7F, 0x10, 0xFA, 0x15, 0xCE, 0xD1, 0xAD, 0x35, 0x85, 0x52, 0x1A, 0x1D, 0x99, 0x5A, 0x89 }, ++ { 0x81, 0x6A, 0xEF, 0x87, 0x59, 0x53, 0x71, 0x6C, 0xD7, 0xA5, 0x81, 0xF7, 0x32, 0xF5, 0x3D, 0xD4, 0x35, 0xDA, 0xB6, 0x6D, 0x09, 0xC3, 0x61, 0xD2, 0xD6, 0x59, 0x2D, 0xE1, 0x77, 0x55, 0xD8, 0xA8 }, ++ { 0x9A, 0x76, 0x89, 0x32, 0x26, 0x69, 0x3B, 0x6E, 0xA9, 0x7E, 0x6A, 0x73, 0x8F, 0x9D, 0x10, 0xFB, 0x3D, 0x0B, 0x43, 0xAE, 0x0E, 0x8B, 0x7D, 0x81, 0x23, 0xEA, 0x76, 0xCE, 0x97, 0x98, 0x9C, 0x7E }, ++ { 0x8D, 0xAE, 0xDB, 0x9A, 0x27, 0x15, 0x29, 0xDB, 0xB7, 0xDC, 0x3B, 0x60, 0x7F, 0xE5, 0xEB, 0x2D, 0x32, 0x11, 0x77, 0x07, 0x58, 0xDD, 0x3B, 0x0A, 0x35, 0x93, 0xD2, 0xD7, 0x95, 0x4E, 0x2D, 0x5B }, ++ { 0x16, 0xDB, 0xC0, 0xAA, 0x5D, 0xD2, 0xC7, 0x74, 0xF5, 0x05, 0x10, 0x0F, 0x73, 0x37, 0x86, 0xD8, 0xA1, 0x75, 0xFC, 0xBB, 0xB5, 0x9C, 0x43, 0xE1, 0xFB, 0xFF, 0x3E, 0x1E, 0xAF, 0x31, 0xCB, 0x4A }, ++ { 0x86, 0x06, 0xCB, 0x89, 0x9C, 0x6A, 0xEA, 0xF5, 0x1B, 0x9D, 0xB0, 0xFE, 0x49, 0x24, 0xA9, 0xFD, 0x5D, 0xAB, 0xC1, 0x9F, 0x88, 0x26, 0xF2, 0xBC, 0x1C, 0x1D, 0x7D, 0xA1, 0x4D, 0x2C, 0x2C, 0x99 }, ++ { 0x84, 0x79, 0x73, 0x1A, 0xED, 0xA5, 0x7B, 0xD3, 0x7E, 0xAD, 0xB5, 0x1A, 0x50, 0x7E, 0x30, 0x7F, 0x3B, 0xD9, 0x5E, 0x69, 0xDB, 0xCA, 0x94, 0xF3, 0xBC, 0x21, 0x72, 0x60, 0x66, 0xAD, 0x6D, 0xFD }, ++ { 0x58, 0x47, 0x3A, 0x9E, 0xA8, 0x2E, 0xFA, 0x3F, 0x3B, 0x3D, 0x8F, 0xC8, 0x3E, 0xD8, 0x86, 0x31, 0x27, 0xB3, 0x3A, 0xE8, 0xDE, 0xAE, 0x63, 0x07, 0x20, 0x1E, 0xDB, 0x6D, 0xDE, 0x61, 0xDE, 0x29 }, ++ { 0x9A, 0x92, 0x55, 0xD5, 0x3A, 0xF1, 0x16, 0xDE, 0x8B, 0xA2, 0x7C, 0xE3, 0x5B, 0x4C, 0x7E, 0x15, 0x64, 0x06, 0x57, 0xA0, 0xFC, 0xB8, 0x88, 0xC7, 0x0D, 0x95, 0x43, 0x1D, 0xAC, 0xD8, 0xF8, 0x30 }, ++ { 0x9E, 0xB0, 0x5F, 0xFB, 0xA3, 0x9F, 0xD8, 0x59, 0x6A, 0x45, 0x49, 0x3E, 0x18, 0xD2, 0x51, 0x0B, 0xF3, 0xEF, 0x06, 0x5C, 0x51, 0xD6, 0xE1, 0x3A, 0xBE, 0x66, 0xAA, 0x57, 0xE0, 0x5C, 0xFD, 0xB7 }, ++ { 0x81, 0xDC, 0xC3, 0xA5, 0x05, 0xEA, 0xCE, 0x3F, 0x87, 0x9D, 0x8F, 0x70, 0x27, 0x76, 0x77, 0x0F, 0x9D, 0xF5, 0x0E, 0x52, 0x1D, 0x14, 0x28, 0xA8, 0x5D, 0xAF, 0x04, 0xF9, 0xAD, 0x21, 0x50, 0xE0 }, ++ { 0xE3, 0xE3, 0xC4, 0xAA, 0x3A, 0xCB, 0xBC, 0x85, 0x33, 0x2A, 0xF9, 0xD5, 0x64, 0xBC, 0x24, 0x16, 0x5E, 0x16, 0x87, 0xF6, 0xB1, 0xAD, 0xCB, 0xFA, 0xE7, 0x7A, 0x8F, 0x03, 0xC7, 0x2A, 0xC2, 0x8C }, ++ { 0x67, 0x46, 0xC8, 0x0B, 0x4E, 0xB5, 0x6A, 0xEA, 0x45, 0xE6, 0x4E, 0x72, 0x89, 0xBB, 0xA3, 0xED, 0xBF, 0x45, 0xEC, 0xF8, 0x20, 0x64, 0x81, 0xFF, 0x63, 0x02, 0x12, 0x29, 0x84, 0xCD, 0x52, 0x6A }, ++ { 0x2B, 0x62, 0x8E, 0x52, 0x76, 0x4D, 0x7D, 0x62, 0xC0, 0x86, 0x8B, 0x21, 0x23, 0x57, 0xCD, 0xD1, 0x2D, 0x91, 0x49, 0x82, 0x2F, 0x4E, 0x98, 0x45, 0xD9, 0x18, 0xA0, 0x8D, 0x1A, 0xE9, 0x90, 0xC0 }, ++ { 0xE4, 0xBF, 0xE8, 0x0D, 0x58, 0xC9, 0x19, 0x94, 0x61, 0x39, 0x09, 0xDC, 0x4B, 0x1A, 0x12, 0x49, 0x68, 0x96, 0xC0, 0x04, 0xAF, 0x7B, 0x57, 0x01, 0x48, 0x3D, 0xE4, 0x5D, 0x28, 0x23, 0xD7, 0x8E }, ++ { 0xEB, 0xB4, 0xBA, 0x15, 0x0C, 0xEF, 0x27, 0x34, 0x34, 0x5B, 0x5D, 0x64, 0x1B, 0xBE, 0xD0, 0x3A, 0x21, 0xEA, 0xFA, 0xE9, 0x33, 0xC9, 0x9E, 0x00, 0x92, 0x12, 0xEF, 0x04, 0x57, 0x4A, 0x85, 0x30 }, ++ { 0x39, 0x66, 0xEC, 0x73, 0xB1, 0x54, 0xAC, 0xC6, 0x97, 0xAC, 0x5C, 0xF5, 0xB2, 0x4B, 0x40, 0xBD, 0xB0, 0xDB, 0x9E, 0x39, 0x88, 0x36, 0xD7, 0x6D, 0x4B, 0x88, 0x0E, 0x3B, 0x2A, 0xF1, 0xAA, 0x27 }, ++ { 0xEF, 0x7E, 0x48, 0x31, 0xB3, 0xA8, 0x46, 0x36, 0x51, 0x8D, 0x6E, 0x4B, 0xFC, 0xE6, 0x4A, 0x43, 0xDB, 0x2A, 0x5D, 0xDA, 0x9C, 0xCA, 0x2B, 0x44, 0xF3, 0x90, 0x33, 0xBD, 0xC4, 0x0D, 0x62, 0x43 }, ++ { 0x7A, 0xBF, 0x6A, 0xCF, 0x5C, 0x8E, 0x54, 0x9D, 0xDB, 0xB1, 0x5A, 0xE8, 0xD8, 0xB3, 0x88, 0xC1, 0xC1, 0x97, 0xE6, 0x98, 0x73, 0x7C, 0x97, 0x85, 0x50, 0x1E, 0xD1, 0xF9, 0x49, 0x30, 0xB7, 0xD9 }, ++ { 0x88, 0x01, 0x8D, 0xED, 0x66, 0x81, 0x3F, 0x0C, 0xA9, 0x5D, 0xEF, 0x47, 0x4C, 0x63, 0x06, 0x92, 0x01, 0x99, 0x67, 0xB9, 0xE3, 0x68, 0x88, 0xDA, 0xDD, 0x94, 0x12, 0x47, 0x19, 0xB6, 0x82, 0xF6 }, ++ { 0x39, 0x30, 0x87, 0x6B, 0x9F, 0xC7, 0x52, 0x90, 0x36, 0xB0, 0x08, 0xB1, 0xB8, 0xBB, 0x99, 0x75, 0x22, 0xA4, 0x41, 0x63, 0x5A, 0x0C, 0x25, 0xEC, 0x02, 0xFB, 0x6D, 0x90, 0x26, 0xE5, 0x5A, 0x97 }, ++ { 0x0A, 0x40, 0x49, 0xD5, 0x7E, 0x83, 0x3B, 0x56, 0x95, 0xFA, 0xC9, 0x3D, 0xD1, 0xFB, 0xEF, 0x31, 0x66, 0xB4, 0x4B, 0x12, 0xAD, 0x11, 0x24, 0x86, 0x62, 0x38, 0x3A, 0xE0, 0x51, 0xE1, 0x58, 0x27 }, ++ { 0x81, 0xDC, 0xC0, 0x67, 0x8B, 0xB6, 0xA7, 0x65, 0xE4, 0x8C, 0x32, 0x09, 0x65, 0x4F, 0xE9, 0x00, 0x89, 0xCE, 0x44, 0xFF, 0x56, 0x18, 0x47, 0x7E, 0x39, 0xAB, 0x28, 0x64, 0x76, 0xDF, 0x05, 0x2B }, ++ { 0xE6, 0x9B, 0x3A, 0x36, 0xA4, 0x46, 0x19, 0x12, 0xDC, 0x08, 0x34, 0x6B, 0x11, 0xDD, 0xCB, 0x9D, 0xB7, 0x96, 0xF8, 0x85, 0xFD, 0x01, 0x93, 0x6E, 0x66, 0x2F, 0xE2, 0x92, 0x97, 0xB0, 0x99, 0xA4 }, ++ { 0x5A, 0xC6, 0x50, 0x3B, 0x0D, 0x8D, 0xA6, 0x91, 0x76, 0x46, 0xE6, 0xDC, 0xC8, 0x7E, 0xDC, 0x58, 0xE9, 0x42, 0x45, 0x32, 0x4C, 0xC2, 0x04, 0xF4, 0xDD, 0x4A, 0xF0, 0x15, 0x63, 0xAC, 0xD4, 0x27 }, ++ { 0xDF, 0x6D, 0xDA, 0x21, 0x35, 0x9A, 0x30, 0xBC, 0x27, 0x17, 0x80, 0x97, 0x1C, 0x1A, 0xBD, 0x56, 0xA6, 0xEF, 0x16, 0x7E, 0x48, 0x08, 0x87, 0x88, 0x8E, 0x73, 0xA8, 0x6D, 0x3B, 0xF6, 0x05, 0xE9 }, ++ { 0xE8, 0xE6, 0xE4, 0x70, 0x71, 0xE7, 0xB7, 0xDF, 0x25, 0x80, 0xF2, 0x25, 0xCF, 0xBB, 0xED, 0xF8, 0x4C, 0xE6, 0x77, 0x46, 0x62, 0x66, 0x28, 0xD3, 0x30, 0x97, 0xE4, 0xB7, 0xDC, 0x57, 0x11, 0x07 }, ++ { 0x53, 0xE4, 0x0E, 0xAD, 0x62, 0x05, 0x1E, 0x19, 0xCB, 0x9B, 0xA8, 0x13, 0x3E, 0x3E, 0x5C, 0x1C, 0xE0, 0x0D, 0xDC, 0xAD, 0x8A, 0xCF, 0x34, 0x2A, 0x22, 0x43, 0x60, 0xB0, 0xAC, 0xC1, 0x47, 0x77 }, ++ { 0x9C, 0xCD, 0x53, 0xFE, 0x80, 0xBE, 0x78, 0x6A, 0xA9, 0x84, 0x63, 0x84, 0x62, 0xFB, 0x28, 0xAF, 0xDF, 0x12, 0x2B, 0x34, 0xD7, 0x8F, 0x46, 0x87, 0xEC, 0x63, 0x2B, 0xB1, 0x9D, 0xE2, 0x37, 0x1A }, ++ { 0xCB, 0xD4, 0x80, 0x52, 0xC4, 0x8D, 0x78, 0x84, 0x66, 0xA3, 0xE8, 0x11, 0x8C, 0x56, 0xC9, 0x7F, 0xE1, 0x46, 0xE5, 0x54, 0x6F, 0xAA, 0xF9, 0x3E, 0x2B, 0xC3, 0xC4, 0x7E, 0x45, 0x93, 0x97, 0x53 }, ++ { 0x25, 0x68, 0x83, 0xB1, 0x4E, 0x2A, 0xF4, 0x4D, 0xAD, 0xB2, 0x8E, 0x1B, 0x34, 0xB2, 0xAC, 0x0F, 0x0F, 0x4C, 0x91, 0xC3, 0x4E, 0xC9, 0x16, 0x9E, 0x29, 0x03, 0x61, 0x58, 0xAC, 0xAA, 0x95, 0xB9 }, ++ { 0x44, 0x71, 0xB9, 0x1A, 0xB4, 0x2D, 0xB7, 0xC4, 0xDD, 0x84, 0x90, 0xAB, 0x95, 0xA2, 0xEE, 0x8D, 0x04, 0xE3, 0xEF, 0x5C, 0x3D, 0x6F, 0xC7, 0x1A, 0xC7, 0x4B, 0x2B, 0x26, 0x91, 0x4D, 0x16, 0x41 }, ++ { 0xA5, 0xEB, 0x08, 0x03, 0x8F, 0x8F, 0x11, 0x55, 0xED, 0x86, 0xE6, 0x31, 0x90, 0x6F, 0xC1, 0x30, 0x95, 0xF6, 0xBB, 0xA4, 0x1D, 0xE5, 0xD4, 0xE7, 0x95, 0x75, 0x8E, 0xC8, 0xC8, 0xDF, 0x8A, 0xF1 }, ++ { 0xDC, 0x1D, 0xB6, 0x4E, 0xD8, 0xB4, 0x8A, 0x91, 0x0E, 0x06, 0x0A, 0x6B, 0x86, 0x63, 0x74, 0xC5, 0x78, 0x78, 0x4E, 0x9A, 0xC4, 0x9A, 0xB2, 0x77, 0x40, 0x92, 0xAC, 0x71, 0x50, 0x19, 0x34, 0xAC }, ++ { 0x28, 0x54, 0x13, 0xB2, 0xF2, 0xEE, 0x87, 0x3D, 0x34, 0x31, 0x9E, 0xE0, 0xBB, 0xFB, 0xB9, 0x0F, 0x32, 0xDA, 0x43, 0x4C, 0xC8, 0x7E, 0x3D, 0xB5, 0xED, 0x12, 0x1B, 0xB3, 0x98, 0xED, 0x96, 0x4B }, ++ { 0x02, 0x16, 0xE0, 0xF8, 0x1F, 0x75, 0x0F, 0x26, 0xF1, 0x99, 0x8B, 0xC3, 0x93, 0x4E, 0x3E, 0x12, 0x4C, 0x99, 0x45, 0xE6, 0x85, 0xA6, 0x0B, 0x25, 0xE8, 0xFB, 0xD9, 0x62, 0x5A, 0xB6, 0xB5, 0x99 }, ++ { 0x38, 0xC4, 0x10, 0xF5, 0xB9, 0xD4, 0x07, 0x20, 0x50, 0x75, 0x5B, 0x31, 0xDC, 0xA8, 0x9F, 0xD5, 0x39, 0x5C, 0x67, 0x85, 0xEE, 0xB3, 0xD7, 0x90, 0xF3, 0x20, 0xFF, 0x94, 0x1C, 0x5A, 0x93, 0xBF }, ++ { 0xF1, 0x84, 0x17, 0xB3, 0x9D, 0x61, 0x7A, 0xB1, 0xC1, 0x8F, 0xDF, 0x91, 0xEB, 0xD0, 0xFC, 0x6D, 0x55, 0x16, 0xBB, 0x34, 0xCF, 0x39, 0x36, 0x40, 0x37, 0xBC, 0xE8, 0x1F, 0xA0, 0x4C, 0xEC, 0xB1 }, ++ { 0x1F, 0xA8, 0x77, 0xDE, 0x67, 0x25, 0x9D, 0x19, 0x86, 0x3A, 0x2A, 0x34, 0xBC, 0xC6, 0x96, 0x2A, 0x2B, 0x25, 0xFC, 0xBF, 0x5C, 0xBE, 0xCD, 0x7E, 0xDE, 0x8F, 0x1F, 0xA3, 0x66, 0x88, 0xA7, 0x96 }, ++ { 0x5B, 0xD1, 0x69, 0xE6, 0x7C, 0x82, 0xC2, 0xC2, 0xE9, 0x8E, 0xF7, 0x00, 0x8B, 0xDF, 0x26, 0x1F, 0x2D, 0xDF, 0x30, 0xB1, 0xC0, 0x0F, 0x9E, 0x7F, 0x27, 0x5B, 0xB3, 0xE8, 0xA2, 0x8D, 0xC9, 0xA2 }, ++ { 0xC8, 0x0A, 0xBE, 0xEB, 0xB6, 0x69, 0xAD, 0x5D, 0xEE, 0xB5, 0xF5, 0xEC, 0x8E, 0xA6, 0xB7, 0xA0, 0x5D, 0xDF, 0x7D, 0x31, 0xEC, 0x4C, 0x0A, 0x2E, 0xE2, 0x0B, 0x0B, 0x98, 0xCA, 0xEC, 0x67, 0x46 }, ++ { 0xE7, 0x6D, 0x3F, 0xBD, 0xA5, 0xBA, 0x37, 0x4E, 0x6B, 0xF8, 0xE5, 0x0F, 0xAD, 0xC3, 0xBB, 0xB9, 0xBA, 0x5C, 0x20, 0x6E, 0xBD, 0xEC, 0x89, 0xA3, 0xA5, 0x4C, 0xF3, 0xDD, 0x84, 0xA0, 0x70, 0x16 }, ++ { 0x7B, 0xBA, 0x9D, 0xC5, 0xB5, 0xDB, 0x20, 0x71, 0xD1, 0x77, 0x52, 0xB1, 0x04, 0x4C, 0x1E, 0xCE, 0xD9, 0x6A, 0xAF, 0x2D, 0xD4, 0x6E, 0x9B, 0x43, 0x37, 0x50, 0xE8, 0xEA, 0x0D, 0xCC, 0x18, 0x70 }, ++ { 0xF2, 0x9B, 0x1B, 0x1A, 0xB9, 0xBA, 0xB1, 0x63, 0x01, 0x8E, 0xE3, 0xDA, 0x15, 0x23, 0x2C, 0xCA, 0x78, 0xEC, 0x52, 0xDB, 0xC3, 0x4E, 0xDA, 0x5B, 0x82, 0x2E, 0xC1, 0xD8, 0x0F, 0xC2, 0x1B, 0xD0 }, ++ { 0x9E, 0xE3, 0xE3, 0xE7, 0xE9, 0x00, 0xF1, 0xE1, 0x1D, 0x30, 0x8C, 0x4B, 0x2B, 0x30, 0x76, 0xD2, 0x72, 0xCF, 0x70, 0x12, 0x4F, 0x9F, 0x51, 0xE1, 0xDA, 0x60, 0xF3, 0x78, 0x46, 0xCD, 0xD2, 0xF4 }, ++ { 0x70, 0xEA, 0x3B, 0x01, 0x76, 0x92, 0x7D, 0x90, 0x96, 0xA1, 0x85, 0x08, 0xCD, 0x12, 0x3A, 0x29, 0x03, 0x25, 0x92, 0x0A, 0x9D, 0x00, 0xA8, 0x9B, 0x5D, 0xE0, 0x42, 0x73, 0xFB, 0xC7, 0x6B, 0x85 }, ++ { 0x67, 0xDE, 0x25, 0xC0, 0x2A, 0x4A, 0xAB, 0xA2, 0x3B, 0xDC, 0x97, 0x3C, 0x8B, 0xB0, 0xB5, 0x79, 0x6D, 0x47, 0xCC, 0x06, 0x59, 0xD4, 0x3D, 0xFF, 0x1F, 0x97, 0xDE, 0x17, 0x49, 0x63, 0xB6, 0x8E }, ++ { 0xB2, 0x16, 0x8E, 0x4E, 0x0F, 0x18, 0xB0, 0xE6, 0x41, 0x00, 0xB5, 0x17, 0xED, 0x95, 0x25, 0x7D, 0x73, 0xF0, 0x62, 0x0D, 0xF8, 0x85, 0xC1, 0x3D, 0x2E, 0xCF, 0x79, 0x36, 0x7B, 0x38, 0x4C, 0xEE }, ++ { 0x2E, 0x7D, 0xEC, 0x24, 0x28, 0x85, 0x3B, 0x2C, 0x71, 0x76, 0x07, 0x45, 0x54, 0x1F, 0x7A, 0xFE, 0x98, 0x25, 0xB5, 0xDD, 0x77, 0xDF, 0x06, 0x51, 0x1D, 0x84, 0x41, 0xA9, 0x4B, 0xAC, 0xC9, 0x27 }, ++ { 0xCA, 0x9F, 0xFA, 0xC4, 0xC4, 0x3F, 0x0B, 0x48, 0x46, 0x1D, 0xC5, 0xC2, 0x63, 0xBE, 0xA3, 0xF6, 0xF0, 0x06, 0x11, 0xCE, 0xAC, 0xAB, 0xF6, 0xF8, 0x95, 0xBA, 0x2B, 0x01, 0x01, 0xDB, 0xB6, 0x8D }, ++ { 0x74, 0x10, 0xD4, 0x2D, 0x8F, 0xD1, 0xD5, 0xE9, 0xD2, 0xF5, 0x81, 0x5C, 0xB9, 0x34, 0x17, 0x99, 0x88, 0x28, 0xEF, 0x3C, 0x42, 0x30, 0xBF, 0xBD, 0x41, 0x2D, 0xF0, 0xA4, 0xA7, 0xA2, 0x50, 0x7A }, ++ { 0x50, 0x10, 0xF6, 0x84, 0x51, 0x6D, 0xCC, 0xD0, 0xB6, 0xEE, 0x08, 0x52, 0xC2, 0x51, 0x2B, 0x4D, 0xC0, 0x06, 0x6C, 0xF0, 0xD5, 0x6F, 0x35, 0x30, 0x29, 0x78, 0xDB, 0x8A, 0xE3, 0x2C, 0x6A, 0x81 }, ++ { 0xAC, 0xAA, 0xB5, 0x85, 0xF7, 0xB7, 0x9B, 0x71, 0x99, 0x35, 0xCE, 0xB8, 0x95, 0x23, 0xDD, 0xC5, 0x48, 0x27, 0xF7, 0x5C, 0x56, 0x88, 0x38, 0x56, 0x15, 0x4A, 0x56, 0xCD, 0xCD, 0x5E, 0xE9, 0x88 }, ++ { 0x66, 0x6D, 0xE5, 0xD1, 0x44, 0x0F, 0xEE, 0x73, 0x31, 0xAA, 0xF0, 0x12, 0x3A, 0x62, 0xEF, 0x2D, 0x8B, 0xA5, 0x74, 0x53, 0xA0, 0x76, 0x96, 0x35, 0xAC, 0x6C, 0xD0, 0x1E, 0x63, 0x3F, 0x77, 0x12 }, ++ { 0xA6, 0xF9, 0x86, 0x58, 0xF6, 0xEA, 0xBA, 0xF9, 0x02, 0xD8, 0xB3, 0x87, 0x1A, 0x4B, 0x10, 0x1D, 0x16, 0x19, 0x6E, 0x8A, 0x4B, 0x24, 0x1E, 0x15, 0x58, 0xFE, 0x29, 0x96, 0x6E, 0x10, 0x3E, 0x8D }, ++ { 0x89, 0x15, 0x46, 0xA8, 0xB2, 0x9F, 0x30, 0x47, 0xDD, 0xCF, 0xE5, 0xB0, 0x0E, 0x45, 0xFD, 0x55, 0x75, 0x63, 0x73, 0x10, 0x5E, 0xA8, 0x63, 0x7D, 0xFC, 0xFF, 0x54, 0x7B, 0x6E, 0xA9, 0x53, 0x5F }, ++ { 0x18, 0xDF, 0xBC, 0x1A, 0xC5, 0xD2, 0x5B, 0x07, 0x61, 0x13, 0x7D, 0xBD, 0x22, 0xC1, 0x7C, 0x82, 0x9D, 0x0F, 0x0E, 0xF1, 0xD8, 0x23, 0x44, 0xE9, 0xC8, 0x9C, 0x28, 0x66, 0x94, 0xDA, 0x24, 0xE8 }, ++ { 0xB5, 0x4B, 0x9B, 0x67, 0xF8, 0xFE, 0xD5, 0x4B, 0xBF, 0x5A, 0x26, 0x66, 0xDB, 0xDF, 0x4B, 0x23, 0xCF, 0xF1, 0xD1, 0xB6, 0xF4, 0xAF, 0xC9, 0x85, 0xB2, 0xE6, 0xD3, 0x30, 0x5A, 0x9F, 0xF8, 0x0F }, ++ { 0x7D, 0xB4, 0x42, 0xE1, 0x32, 0xBA, 0x59, 0xBC, 0x12, 0x89, 0xAA, 0x98, 0xB0, 0xD3, 0xE8, 0x06, 0x00, 0x4F, 0x8E, 0xC1, 0x28, 0x11, 0xAF, 0x1E, 0x2E, 0x33, 0xC6, 0x9B, 0xFD, 0xE7, 0x29, 0xE1 }, ++ { 0x25, 0x0F, 0x37, 0xCD, 0xC1, 0x5E, 0x81, 0x7D, 0x2F, 0x16, 0x0D, 0x99, 0x56, 0xC7, 0x1F, 0xE3, 0xEB, 0x5D, 0xB7, 0x45, 0x56, 0xE4, 0xAD, 0xF9, 0xA4, 0xFF, 0xAF, 0xBA, 0x74, 0x01, 0x03, 0x96 }, ++ { 0x4A, 0xB8, 0xA3, 0xDD, 0x1D, 0xDF, 0x8A, 0xD4, 0x3D, 0xAB, 0x13, 0xA2, 0x7F, 0x66, 0xA6, 0x54, 0x4F, 0x29, 0x05, 0x97, 0xFA, 0x96, 0x04, 0x0E, 0x0E, 0x1D, 0xB9, 0x26, 0x3A, 0xA4, 0x79, 0xF8 }, ++ { 0xEE, 0x61, 0x72, 0x7A, 0x07, 0x66, 0xDF, 0x93, 0x9C, 0xCD, 0xC8, 0x60, 0x33, 0x40, 0x44, 0xC7, 0x9A, 0x3C, 0x9B, 0x15, 0x62, 0x00, 0xBC, 0x3A, 0xA3, 0x29, 0x73, 0x48, 0x3D, 0x83, 0x41, 0xAE }, ++ { 0x3F, 0x68, 0xC7, 0xEC, 0x63, 0xAC, 0x11, 0xEB, 0xB9, 0x8F, 0x94, 0xB3, 0x39, 0xB0, 0x5C, 0x10, 0x49, 0x84, 0xFD, 0xA5, 0x01, 0x03, 0x06, 0x01, 0x44, 0xE5, 0xA2, 0xBF, 0xCC, 0xC9, 0xDA, 0x95 }, ++ { 0x05, 0x6F, 0x29, 0x81, 0x6B, 0x8A, 0xF8, 0xF5, 0x66, 0x82, 0xBC, 0x4D, 0x7C, 0xF0, 0x94, 0x11, 0x1D, 0xA7, 0x73, 0x3E, 0x72, 0x6C, 0xD1, 0x3D, 0x6B, 0x3E, 0x8E, 0xA0, 0x3E, 0x92, 0xA0, 0xD5 }, ++ { 0xF5, 0xEC, 0x43, 0xA2, 0x8A, 0xCB, 0xEF, 0xF1, 0xF3, 0x31, 0x8A, 0x5B, 0xCA, 0xC7, 0xC6, 0x6D, 0xDB, 0x52, 0x30, 0xB7, 0x9D, 0xB2, 0xD1, 0x05, 0xBC, 0xBE, 0x15, 0xF3, 0xC1, 0x14, 0x8D, 0x69 }, ++ { 0x2A, 0x69, 0x60, 0xAD, 0x1D, 0x8D, 0xD5, 0x47, 0x55, 0x5C, 0xFB, 0xD5, 0xE4, 0x60, 0x0F, 0x1E, 0xAA, 0x1C, 0x8E, 0xDA, 0x34, 0xDE, 0x03, 0x74, 0xEC, 0x4A, 0x26, 0xEA, 0xAA, 0xA3, 0x3B, 0x4E }, ++ { 0xDC, 0xC1, 0xEA, 0x7B, 0xAA, 0xB9, 0x33, 0x84, 0xF7, 0x6B, 0x79, 0x68, 0x66, 0x19, 0x97, 0x54, 0x74, 0x2F, 0x7B, 0x96, 0xD6, 0xB4, 0xC1, 0x20, 0x16, 0x5C, 0x04, 0xA6, 0xC4, 0xF5, 0xCE, 0x10 }, ++ { 0x13, 0xD5, 0xDF, 0x17, 0x92, 0x21, 0x37, 0x9C, 0x6A, 0x78, 0xC0, 0x7C, 0x79, 0x3F, 0xF5, 0x34, 0x87, 0xCA, 0xE6, 0xBF, 0x9F, 0xE8, 0x82, 0x54, 0x1A, 0xB0, 0xE7, 0x35, 0xE3, 0xEA, 0xDA, 0x3B }, ++ { 0x8C, 0x59, 0xE4, 0x40, 0x76, 0x41, 0xA0, 0x1E, 0x8F, 0xF9, 0x1F, 0x99, 0x80, 0xDC, 0x23, 0x6F, 0x4E, 0xCD, 0x6F, 0xCF, 0x52, 0x58, 0x9A, 0x09, 0x9A, 0x96, 0x16, 0x33, 0x96, 0x77, 0x14, 0xE1 }, ++ { 0x83, 0x3B, 0x1A, 0xC6, 0xA2, 0x51, 0xFD, 0x08, 0xFD, 0x6D, 0x90, 0x8F, 0xEA, 0x2A, 0x4E, 0xE1, 0xE0, 0x40, 0xBC, 0xA9, 0x3F, 0xC1, 0xA3, 0x8E, 0xC3, 0x82, 0x0E, 0x0C, 0x10, 0xBD, 0x82, 0xEA }, ++ { 0xA2, 0x44, 0xF9, 0x27, 0xF3, 0xB4, 0x0B, 0x8F, 0x6C, 0x39, 0x15, 0x70, 0xC7, 0x65, 0x41, 0x8F, 0x2F, 0x6E, 0x70, 0x8E, 0xAC, 0x90, 0x06, 0xC5, 0x1A, 0x7F, 0xEF, 0xF4, 0xAF, 0x3B, 0x2B, 0x9E }, ++ { 0x3D, 0x99, 0xED, 0x95, 0x50, 0xCF, 0x11, 0x96, 0xE6, 0xC4, 0xD2, 0x0C, 0x25, 0x96, 0x20, 0xF8, 0x58, 0xC3, 0xD7, 0x03, 0x37, 0x4C, 0x12, 0x8C, 0xE7, 0xB5, 0x90, 0x31, 0x0C, 0x83, 0x04, 0x6D }, ++ { 0x2B, 0x35, 0xC4, 0x7D, 0x7B, 0x87, 0x76, 0x1F, 0x0A, 0xE4, 0x3A, 0xC5, 0x6A, 0xC2, 0x7B, 0x9F, 0x25, 0x83, 0x03, 0x67, 0xB5, 0x95, 0xBE, 0x8C, 0x24, 0x0E, 0x94, 0x60, 0x0C, 0x6E, 0x33, 0x12 }, ++ { 0x5D, 0x11, 0xED, 0x37, 0xD2, 0x4D, 0xC7, 0x67, 0x30, 0x5C, 0xB7, 0xE1, 0x46, 0x7D, 0x87, 0xC0, 0x65, 0xAC, 0x4B, 0xC8, 0xA4, 0x26, 0xDE, 0x38, 0x99, 0x1F, 0xF5, 0x9A, 0xA8, 0x73, 0x5D, 0x02 }, ++ { 0xB8, 0x36, 0x47, 0x8E, 0x1C, 0xA0, 0x64, 0x0D, 0xCE, 0x6F, 0xD9, 0x10, 0xA5, 0x09, 0x62, 0x72, 0xC8, 0x33, 0x09, 0x90, 0xCD, 0x97, 0x86, 0x4A, 0xC2, 0xBF, 0x14, 0xEF, 0x6B, 0x23, 0x91, 0x4A }, ++ { 0x91, 0x00, 0xF9, 0x46, 0xD6, 0xCC, 0xDE, 0x3A, 0x59, 0x7F, 0x90, 0xD3, 0x9F, 0xC1, 0x21, 0x5B, 0xAD, 0xDC, 0x74, 0x13, 0x64, 0x3D, 0x85, 0xC2, 0x1C, 0x3E, 0xEE, 0x5D, 0x2D, 0xD3, 0x28, 0x94 }, ++ { 0xDA, 0x70, 0xEE, 0xDD, 0x23, 0xE6, 0x63, 0xAA, 0x1A, 0x74, 0xB9, 0x76, 0x69, 0x35, 0xB4, 0x79, 0x22, 0x2A, 0x72, 0xAF, 0xBA, 0x5C, 0x79, 0x51, 0x58, 0xDA, 0xD4, 0x1A, 0x3B, 0xD7, 0x7E, 0x40 }, ++ { 0xF0, 0x67, 0xED, 0x6A, 0x0D, 0xBD, 0x43, 0xAA, 0x0A, 0x92, 0x54, 0xE6, 0x9F, 0xD6, 0x6B, 0xDD, 0x8A, 0xCB, 0x87, 0xDE, 0x93, 0x6C, 0x25, 0x8C, 0xFB, 0x02, 0x28, 0x5F, 0x2C, 0x11, 0xFA, 0x79 }, ++ { 0x71, 0x5C, 0x99, 0xC7, 0xD5, 0x75, 0x80, 0xCF, 0x97, 0x53, 0xB4, 0xC1, 0xD7, 0x95, 0xE4, 0x5A, 0x83, 0xFB, 0xB2, 0x28, 0xC0, 0xD3, 0x6F, 0xBE, 0x20, 0xFA, 0xF3, 0x9B, 0xDD, 0x6D, 0x4E, 0x85 }, ++ { 0xE4, 0x57, 0xD6, 0xAD, 0x1E, 0x67, 0xCB, 0x9B, 0xBD, 0x17, 0xCB, 0xD6, 0x98, 0xFA, 0x6D, 0x7D, 0xAE, 0x0C, 0x9B, 0x7A, 0xD6, 0xCB, 0xD6, 0x53, 0x96, 0x34, 0xE3, 0x2A, 0x71, 0x9C, 0x84, 0x92 }, ++ { 0xEC, 0xE3, 0xEA, 0x81, 0x03, 0xE0, 0x24, 0x83, 0xC6, 0x4A, 0x70, 0xA4, 0xBD, 0xCE, 0xE8, 0xCE, 0xB6, 0x27, 0x8F, 0x25, 0x33, 0xF3, 0xF4, 0x8D, 0xBE, 0xED, 0xFB, 0xA9, 0x45, 0x31, 0xD4, 0xAE }, ++ { 0x38, 0x8A, 0xA5, 0xD3, 0x66, 0x7A, 0x97, 0xC6, 0x8D, 0x3D, 0x56, 0xF8, 0xF3, 0xEE, 0x8D, 0x3D, 0x36, 0x09, 0x1F, 0x17, 0xFE, 0x5D, 0x1B, 0x0D, 0x5D, 0x84, 0xC9, 0x3B, 0x2F, 0xFE, 0x40, 0xBD }, ++ { 0x8B, 0x6B, 0x31, 0xB9, 0xAD, 0x7C, 0x3D, 0x5C, 0xD8, 0x4B, 0xF9, 0x89, 0x47, 0xB9, 0xCD, 0xB5, 0x9D, 0xF8, 0xA2, 0x5F, 0xF7, 0x38, 0x10, 0x10, 0x13, 0xBE, 0x4F, 0xD6, 0x5E, 0x1D, 0xD1, 0xA3 }, ++ { 0x06, 0x62, 0x91, 0xF6, 0xBB, 0xD2, 0x5F, 0x3C, 0x85, 0x3D, 0xB7, 0xD8, 0xB9, 0x5C, 0x9A, 0x1C, 0xFB, 0x9B, 0xF1, 0xC1, 0xC9, 0x9F, 0xB9, 0x5A, 0x9B, 0x78, 0x69, 0xD9, 0x0F, 0x1C, 0x29, 0x03 }, ++ { 0xA7, 0x07, 0xEF, 0xBC, 0xCD, 0xCE, 0xED, 0x42, 0x96, 0x7A, 0x66, 0xF5, 0x53, 0x9B, 0x93, 0xED, 0x75, 0x60, 0xD4, 0x67, 0x30, 0x40, 0x16, 0xC4, 0x78, 0x0D, 0x77, 0x55, 0xA5, 0x65, 0xD4, 0xC4 }, ++ { 0x38, 0xC5, 0x3D, 0xFB, 0x70, 0xBE, 0x7E, 0x79, 0x2B, 0x07, 0xA6, 0xA3, 0x5B, 0x8A, 0x6A, 0x0A, 0xBA, 0x02, 0xC5, 0xC5, 0xF3, 0x8B, 0xAF, 0x5C, 0x82, 0x3F, 0xDF, 0xD9, 0xE4, 0x2D, 0x65, 0x7E }, ++ { 0xF2, 0x91, 0x13, 0x86, 0x50, 0x1D, 0x9A, 0xB9, 0xD7, 0x20, 0xCF, 0x8A, 0xD1, 0x05, 0x03, 0xD5, 0x63, 0x4B, 0xF4, 0xB7, 0xD1, 0x2B, 0x56, 0xDF, 0xB7, 0x4F, 0xEC, 0xC6, 0xE4, 0x09, 0x3F, 0x68 }, ++ { 0xC6, 0xF2, 0xBD, 0xD5, 0x2B, 0x81, 0xE6, 0xE4, 0xF6, 0x59, 0x5A, 0xBD, 0x4D, 0x7F, 0xB3, 0x1F, 0x65, 0x11, 0x69, 0xD0, 0x0F, 0xF3, 0x26, 0x92, 0x6B, 0x34, 0x94, 0x7B, 0x28, 0xA8, 0x39, 0x59 }, ++ { 0x29, 0x3D, 0x94, 0xB1, 0x8C, 0x98, 0xBB, 0x32, 0x23, 0x36, 0x6B, 0x8C, 0xE7, 0x4C, 0x28, 0xFB, 0xDF, 0x28, 0xE1, 0xF8, 0x4A, 0x33, 0x50, 0xB0, 0xEB, 0x2D, 0x18, 0x04, 0xA5, 0x77, 0x57, 0x9B }, ++ { 0x2C, 0x2F, 0xA5, 0xC0, 0xB5, 0x15, 0x33, 0x16, 0x5B, 0xC3, 0x75, 0xC2, 0x2E, 0x27, 0x81, 0x76, 0x82, 0x70, 0xA3, 0x83, 0x98, 0x5D, 0x13, 0xBD, 0x6B, 0x67, 0xB6, 0xFD, 0x67, 0xF8, 0x89, 0xEB }, ++ { 0xCA, 0xA0, 0x9B, 0x82, 0xB7, 0x25, 0x62, 0xE4, 0x3F, 0x4B, 0x22, 0x75, 0xC0, 0x91, 0x91, 0x8E, 0x62, 0x4D, 0x91, 0x16, 0x61, 0xCC, 0x81, 0x1B, 0xB5, 0xFA, 0xEC, 0x51, 0xF6, 0x08, 0x8E, 0xF7 }, ++ { 0x24, 0x76, 0x1E, 0x45, 0xE6, 0x74, 0x39, 0x53, 0x79, 0xFB, 0x17, 0x72, 0x9C, 0x78, 0xCB, 0x93, 0x9E, 0x6F, 0x74, 0xC5, 0xDF, 0xFB, 0x9C, 0x96, 0x1F, 0x49, 0x59, 0x82, 0xC3, 0xED, 0x1F, 0xE3 }, ++ { 0x55, 0xB7, 0x0A, 0x82, 0x13, 0x1E, 0xC9, 0x48, 0x88, 0xD7, 0xAB, 0x54, 0xA7, 0xC5, 0x15, 0x25, 0x5C, 0x39, 0x38, 0xBB, 0x10, 0xBC, 0x78, 0x4D, 0xC9, 0xB6, 0x7F, 0x07, 0x6E, 0x34, 0x1A, 0x73 }, ++ { 0x6A, 0xB9, 0x05, 0x7B, 0x97, 0x7E, 0xBC, 0x3C, 0xA4, 0xD4, 0xCE, 0x74, 0x50, 0x6C, 0x25, 0xCC, 0xCD, 0xC5, 0x66, 0x49, 0x7C, 0x45, 0x0B, 0x54, 0x15, 0xA3, 0x94, 0x86, 0xF8, 0x65, 0x7A, 0x03 }, ++ { 0x24, 0x06, 0x6D, 0xEE, 0xE0, 0xEC, 0xEE, 0x15, 0xA4, 0x5F, 0x0A, 0x32, 0x6D, 0x0F, 0x8D, 0xBC, 0x79, 0x76, 0x1E, 0xBB, 0x93, 0xCF, 0x8C, 0x03, 0x77, 0xAF, 0x44, 0x09, 0x78, 0xFC, 0xF9, 0x94 }, ++ { 0x20, 0x00, 0x0D, 0x3F, 0x66, 0xBA, 0x76, 0x86, 0x0D, 0x5A, 0x95, 0x06, 0x88, 0xB9, 0xAA, 0x0D, 0x76, 0xCF, 0xEA, 0x59, 0xB0, 0x05, 0xD8, 0x59, 0x91, 0x4B, 0x1A, 0x46, 0x65, 0x3A, 0x93, 0x9B }, ++ { 0xB9, 0x2D, 0xAA, 0x79, 0x60, 0x3E, 0x3B, 0xDB, 0xC3, 0xBF, 0xE0, 0xF4, 0x19, 0xE4, 0x09, 0xB2, 0xEA, 0x10, 0xDC, 0x43, 0x5B, 0xEE, 0xFE, 0x29, 0x59, 0xDA, 0x16, 0x89, 0x5D, 0x5D, 0xCA, 0x1C }, ++ { 0xE9, 0x47, 0x94, 0x87, 0x05, 0xB2, 0x06, 0xD5, 0x72, 0xB0, 0xE8, 0xF6, 0x2F, 0x66, 0xA6, 0x55, 0x1C, 0xBD, 0x6B, 0xC3, 0x05, 0xD2, 0x6C, 0xE7, 0x53, 0x9A, 0x12, 0xF9, 0xAA, 0xDF, 0x75, 0x71 }, ++ { 0x3D, 0x67, 0xC1, 0xB3, 0xF9, 0xB2, 0x39, 0x10, 0xE3, 0xD3, 0x5E, 0x6B, 0x0F, 0x2C, 0xCF, 0x44, 0xA0, 0xB5, 0x40, 0xA4, 0x5C, 0x18, 0xBA, 0x3C, 0x36, 0x26, 0x4D, 0xD4, 0x8E, 0x96, 0xAF, 0x6A }, ++ { 0xC7, 0x55, 0x8B, 0xAB, 0xDA, 0x04, 0xBC, 0xCB, 0x76, 0x4D, 0x0B, 0xBF, 0x33, 0x58, 0x42, 0x51, 0x41, 0x90, 0x2D, 0x22, 0x39, 0x1D, 0x9F, 0x8C, 0x59, 0x15, 0x9F, 0xEC, 0x9E, 0x49, 0xB1, 0x51 }, ++ { 0x0B, 0x73, 0x2B, 0xB0, 0x35, 0x67, 0x5A, 0x50, 0xFF, 0x58, 0xF2, 0xC2, 0x42, 0xE4, 0x71, 0x0A, 0xEC, 0xE6, 0x46, 0x70, 0x07, 0x9C, 0x13, 0x04, 0x4C, 0x79, 0xC9, 0xB7, 0x49, 0x1F, 0x70, 0x00 }, ++ { 0xD1, 0x20, 0xB5, 0xEF, 0x6D, 0x57, 0xEB, 0xF0, 0x6E, 0xAF, 0x96, 0xBC, 0x93, 0x3C, 0x96, 0x7B, 0x16, 0xCB, 0xE6, 0xE2, 0xBF, 0x00, 0x74, 0x1C, 0x30, 0xAA, 0x1C, 0x54, 0xBA, 0x64, 0x80, 0x1F }, ++ { 0x58, 0xD2, 0x12, 0xAD, 0x6F, 0x58, 0xAE, 0xF0, 0xF8, 0x01, 0x16, 0xB4, 0x41, 0xE5, 0x7F, 0x61, 0x95, 0xBF, 0xEF, 0x26, 0xB6, 0x14, 0x63, 0xED, 0xEC, 0x11, 0x83, 0xCD, 0xB0, 0x4F, 0xE7, 0x6D }, ++ { 0xB8, 0x83, 0x6F, 0x51, 0xD1, 0xE2, 0x9B, 0xDF, 0xDB, 0xA3, 0x25, 0x56, 0x53, 0x60, 0x26, 0x8B, 0x8F, 0xAD, 0x62, 0x74, 0x73, 0xED, 0xEC, 0xEF, 0x7E, 0xAE, 0xFE, 0xE8, 0x37, 0xC7, 0x40, 0x03 }, ++ { 0xC5, 0x47, 0xA3, 0xC1, 0x24, 0xAE, 0x56, 0x85, 0xFF, 0xA7, 0xB8, 0xED, 0xAF, 0x96, 0xEC, 0x86, 0xF8, 0xB2, 0xD0, 0xD5, 0x0C, 0xEE, 0x8B, 0xE3, 0xB1, 0xF0, 0xC7, 0x67, 0x63, 0x06, 0x9D, 0x9C }, ++ { 0x5D, 0x16, 0x8B, 0x76, 0x9A, 0x2F, 0x67, 0x85, 0x3D, 0x62, 0x95, 0xF7, 0x56, 0x8B, 0xE4, 0x0B, 0xB7, 0xA1, 0x6B, 0x8D, 0x65, 0xBA, 0x87, 0x63, 0x5D, 0x19, 0x78, 0xD2, 0xAB, 0x11, 0xBA, 0x2A }, ++ { 0xA2, 0xF6, 0x75, 0xDC, 0x73, 0x02, 0x63, 0x8C, 0xB6, 0x02, 0x01, 0x06, 0x4C, 0xA5, 0x50, 0x77, 0x71, 0x4D, 0x71, 0xFE, 0x09, 0x6A, 0x31, 0x5F, 0x2F, 0xE7, 0x40, 0x12, 0x77, 0xCA, 0xA5, 0xAF }, ++ { 0xC8, 0xAA, 0xB5, 0xCD, 0x01, 0x60, 0xAE, 0x78, 0xCD, 0x2E, 0x8A, 0xC5, 0xFB, 0x0E, 0x09, 0x3C, 0xDB, 0x5C, 0x4B, 0x60, 0x52, 0xA0, 0xA9, 0x7B, 0xB0, 0x42, 0x16, 0x82, 0x6F, 0xA7, 0xA4, 0x37 }, ++ { 0xFF, 0x68, 0xCA, 0x40, 0x35, 0xBF, 0xEB, 0x43, 0xFB, 0xF1, 0x45, 0xFD, 0xDD, 0x5E, 0x43, 0xF1, 0xCE, 0xA5, 0x4F, 0x11, 0xF7, 0xBE, 0xE1, 0x30, 0x58, 0xF0, 0x27, 0x32, 0x9A, 0x4A, 0x5F, 0xA4 }, ++ { 0x1D, 0x4E, 0x54, 0x87, 0xAE, 0x3C, 0x74, 0x0F, 0x2B, 0xA6, 0xE5, 0x41, 0xAC, 0x91, 0xBC, 0x2B, 0xFC, 0xD2, 0x99, 0x9C, 0x51, 0x8D, 0x80, 0x7B, 0x42, 0x67, 0x48, 0x80, 0x3A, 0x35, 0x0F, 0xD4 }, ++ { 0x6D, 0x24, 0x4E, 0x1A, 0x06, 0xCE, 0x4E, 0xF5, 0x78, 0xDD, 0x0F, 0x63, 0xAF, 0xF0, 0x93, 0x67, 0x06, 0x73, 0x51, 0x19, 0xCA, 0x9C, 0x8D, 0x22, 0xD8, 0x6C, 0x80, 0x14, 0x14, 0xAB, 0x97, 0x41 }, ++ { 0xDE, 0xCF, 0x73, 0x29, 0xDB, 0xCC, 0x82, 0x7B, 0x8F, 0xC5, 0x24, 0xC9, 0x43, 0x1E, 0x89, 0x98, 0x02, 0x9E, 0xCE, 0x12, 0xCE, 0x93, 0xB7, 0xB2, 0xF3, 0xE7, 0x69, 0xA9, 0x41, 0xFB, 0x8C, 0xEA }, ++ { 0x2F, 0xAF, 0xCC, 0x0F, 0x2E, 0x63, 0xCB, 0xD0, 0x77, 0x55, 0xBE, 0x7B, 0x75, 0xEC, 0xEA, 0x0A, 0xDF, 0xF9, 0xAA, 0x5E, 0xDE, 0x2A, 0x52, 0xFD, 0xAB, 0x4D, 0xFD, 0x03, 0x74, 0xCD, 0x48, 0x3F }, ++ { 0xAA, 0x85, 0x01, 0x0D, 0xD4, 0x6A, 0x54, 0x6B, 0x53, 0x5E, 0xF4, 0xCF, 0x5F, 0x07, 0xD6, 0x51, 0x61, 0xE8, 0x98, 0x28, 0xF3, 0xA7, 0x7D, 0xB7, 0xB9, 0xB5, 0x6F, 0x0D, 0xF5, 0x9A, 0xAE, 0x45 }, ++ { 0x07, 0xE8, 0xE1, 0xEE, 0x73, 0x2C, 0xB0, 0xD3, 0x56, 0xC9, 0xC0, 0xD1, 0x06, 0x9C, 0x89, 0xD1, 0x7A, 0xDF, 0x6A, 0x9A, 0x33, 0x4F, 0x74, 0x5E, 0xC7, 0x86, 0x73, 0x32, 0x54, 0x8C, 0xA8, 0xE9 }, ++ { 0x0E, 0x01, 0xE8, 0x1C, 0xAD, 0xA8, 0x16, 0x2B, 0xFD, 0x5F, 0x8A, 0x8C, 0x81, 0x8A, 0x6C, 0x69, 0xFE, 0xDF, 0x02, 0xCE, 0xB5, 0x20, 0x85, 0x23, 0xCB, 0xE5, 0x31, 0x3B, 0x89, 0xCA, 0x10, 0x53 }, ++ { 0x6B, 0xB6, 0xC6, 0x47, 0x26, 0x55, 0x08, 0x43, 0x99, 0x85, 0x2E, 0x00, 0x24, 0x9F, 0x8C, 0xB2, 0x47, 0x89, 0x6D, 0x39, 0x2B, 0x02, 0xD7, 0x3B, 0x7F, 0x0D, 0xD8, 0x18, 0xE1, 0xE2, 0x9B, 0x07 }, ++ { 0x42, 0xD4, 0x63, 0x6E, 0x20, 0x60, 0xF0, 0x8F, 0x41, 0xC8, 0x82, 0xE7, 0x6B, 0x39, 0x6B, 0x11, 0x2E, 0xF6, 0x27, 0xCC, 0x24, 0xC4, 0x3D, 0xD5, 0xF8, 0x3A, 0x1D, 0x1A, 0x7E, 0xAD, 0x71, 0x1A }, ++ { 0x48, 0x58, 0xC9, 0xA1, 0x88, 0xB0, 0x23, 0x4F, 0xB9, 0xA8, 0xD4, 0x7D, 0x0B, 0x41, 0x33, 0x65, 0x0A, 0x03, 0x0B, 0xD0, 0x61, 0x1B, 0x87, 0xC3, 0x89, 0x2E, 0x94, 0x95, 0x1F, 0x8D, 0xF8, 0x52 }, ++ { 0x3F, 0xAB, 0x3E, 0x36, 0x98, 0x8D, 0x44, 0x5A, 0x51, 0xC8, 0x78, 0x3E, 0x53, 0x1B, 0xE3, 0xA0, 0x2B, 0xE4, 0x0C, 0xD0, 0x47, 0x96, 0xCF, 0xB6, 0x1D, 0x40, 0x34, 0x74, 0x42, 0xD3, 0xF7, 0x94 }, ++ { 0xEB, 0xAB, 0xC4, 0x96, 0x36, 0xBD, 0x43, 0x3D, 0x2E, 0xC8, 0xF0, 0xE5, 0x18, 0x73, 0x2E, 0xF8, 0xFA, 0x21, 0xD4, 0xD0, 0x71, 0xCC, 0x3B, 0xC4, 0x6C, 0xD7, 0x9F, 0xA3, 0x8A, 0x28, 0xB8, 0x10 }, ++ { 0xA1, 0xD0, 0x34, 0x35, 0x23, 0xB8, 0x93, 0xFC, 0xA8, 0x4F, 0x47, 0xFE, 0xB4, 0xA6, 0x4D, 0x35, 0x0A, 0x17, 0xD8, 0xEE, 0xF5, 0x49, 0x7E, 0xCE, 0x69, 0x7D, 0x02, 0xD7, 0x91, 0x78, 0xB5, 0x91 }, ++ { 0x26, 0x2E, 0xBF, 0xD9, 0x13, 0x0B, 0x7D, 0x28, 0x76, 0x0D, 0x08, 0xEF, 0x8B, 0xFD, 0x3B, 0x86, 0xCD, 0xD3, 0xB2, 0x11, 0x3D, 0x2C, 0xAE, 0xF7, 0xEA, 0x95, 0x1A, 0x30, 0x3D, 0xFA, 0x38, 0x46 }, ++ { 0xF7, 0x61, 0x58, 0xED, 0xD5, 0x0A, 0x15, 0x4F, 0xA7, 0x82, 0x03, 0xED, 0x23, 0x62, 0x93, 0x2F, 0xCB, 0x82, 0x53, 0xAA, 0xE3, 0x78, 0x90, 0x3E, 0xDE, 0xD1, 0xE0, 0x3F, 0x70, 0x21, 0xA2, 0x57 }, ++ { 0x26, 0x17, 0x8E, 0x95, 0x0A, 0xC7, 0x22, 0xF6, 0x7A, 0xE5, 0x6E, 0x57, 0x1B, 0x28, 0x4C, 0x02, 0x07, 0x68, 0x4A, 0x63, 0x34, 0xA1, 0x77, 0x48, 0xA9, 0x4D, 0x26, 0x0B, 0xC5, 0xF5, 0x52, 0x74 }, ++ { 0xC3, 0x78, 0xD1, 0xE4, 0x93, 0xB4, 0x0E, 0xF1, 0x1F, 0xE6, 0xA1, 0x5D, 0x9C, 0x27, 0x37, 0xA3, 0x78, 0x09, 0x63, 0x4C, 0x5A, 0xBA, 0xD5, 0xB3, 0x3D, 0x7E, 0x39, 0x3B, 0x4A, 0xE0, 0x5D, 0x03 }, ++ { 0x98, 0x4B, 0xD8, 0x37, 0x91, 0x01, 0xBE, 0x8F, 0xD8, 0x06, 0x12, 0xD8, 0xEA, 0x29, 0x59, 0xA7, 0x86, 0x5E, 0xC9, 0x71, 0x85, 0x23, 0x55, 0x01, 0x07, 0xAE, 0x39, 0x38, 0xDF, 0x32, 0x01, 0x1B }, ++ { 0xC6, 0xF2, 0x5A, 0x81, 0x2A, 0x14, 0x48, 0x58, 0xAC, 0x5C, 0xED, 0x37, 0xA9, 0x3A, 0x9F, 0x47, 0x59, 0xBA, 0x0B, 0x1C, 0x0F, 0xDC, 0x43, 0x1D, 0xCE, 0x35, 0xF9, 0xEC, 0x1F, 0x1F, 0x4A, 0x99 }, ++ { 0x92, 0x4C, 0x75, 0xC9, 0x44, 0x24, 0xFF, 0x75, 0xE7, 0x4B, 0x8B, 0x4E, 0x94, 0x35, 0x89, 0x58, 0xB0, 0x27, 0xB1, 0x71, 0xDF, 0x5E, 0x57, 0x89, 0x9A, 0xD0, 0xD4, 0xDA, 0xC3, 0x73, 0x53, 0xB6 }, ++ { 0x0A, 0xF3, 0x58, 0x92, 0xA6, 0x3F, 0x45, 0x93, 0x1F, 0x68, 0x46, 0xED, 0x19, 0x03, 0x61, 0xCD, 0x07, 0x30, 0x89, 0xE0, 0x77, 0x16, 0x57, 0x14, 0xB5, 0x0B, 0x81, 0xA2, 0xE3, 0xDD, 0x9B, 0xA1 }, ++ { 0xCC, 0x80, 0xCE, 0xFB, 0x26, 0xC3, 0xB2, 0xB0, 0xDA, 0xEF, 0x23, 0x3E, 0x60, 0x6D, 0x5F, 0xFC, 0x80, 0xFA, 0x17, 0x42, 0x7D, 0x18, 0xE3, 0x04, 0x89, 0x67, 0x3E, 0x06, 0xEF, 0x4B, 0x87, 0xF7 }, ++ { 0xC2, 0xF8, 0xC8, 0x11, 0x74, 0x47, 0xF3, 0x97, 0x8B, 0x08, 0x18, 0xDC, 0xF6, 0xF7, 0x01, 0x16, 0xAC, 0x56, 0xFD, 0x18, 0x4D, 0xD1, 0x27, 0x84, 0x94, 0xE1, 0x03, 0xFC, 0x6D, 0x74, 0xA8, 0x87 }, ++ { 0xBD, 0xEC, 0xF6, 0xBF, 0xC1, 0xBA, 0x0D, 0xF6, 0xE8, 0x62, 0xC8, 0x31, 0x99, 0x22, 0x07, 0x79, 0x6A, 0xCC, 0x79, 0x79, 0x68, 0x35, 0x88, 0x28, 0xC0, 0x6E, 0x7A, 0x51, 0xE0, 0x90, 0x09, 0x8F }, ++ { 0x24, 0xD1, 0xA2, 0x6E, 0x3D, 0xAB, 0x02, 0xFE, 0x45, 0x72, 0xD2, 0xAA, 0x7D, 0xBD, 0x3E, 0xC3, 0x0F, 0x06, 0x93, 0xDB, 0x26, 0xF2, 0x73, 0xD0, 0xAB, 0x2C, 0xB0, 0xC1, 0x3B, 0x5E, 0x64, 0x51 }, ++ { 0xEC, 0x56, 0xF5, 0x8B, 0x09, 0x29, 0x9A, 0x30, 0x0B, 0x14, 0x05, 0x65, 0xD7, 0xD3, 0xE6, 0x87, 0x82, 0xB6, 0xE2, 0xFB, 0xEB, 0x4B, 0x7E, 0xA9, 0x7A, 0xC0, 0x57, 0x98, 0x90, 0x61, 0xDD, 0x3F }, ++ { 0x11, 0xA4, 0x37, 0xC1, 0xAB, 0xA3, 0xC1, 0x19, 0xDD, 0xFA, 0xB3, 0x1B, 0x3E, 0x8C, 0x84, 0x1D, 0xEE, 0xEB, 0x91, 0x3E, 0xF5, 0x7F, 0x7E, 0x48, 0xF2, 0xC9, 0xCF, 0x5A, 0x28, 0xFA, 0x42, 0xBC }, ++ { 0x53, 0xC7, 0xE6, 0x11, 0x4B, 0x85, 0x0A, 0x2C, 0xB4, 0x96, 0xC9, 0xB3, 0xC6, 0x9A, 0x62, 0x3E, 0xAE, 0xA2, 0xCB, 0x1D, 0x33, 0xDD, 0x81, 0x7E, 0x47, 0x65, 0xED, 0xAA, 0x68, 0x23, 0xC2, 0x28 }, ++ { 0x15, 0x4C, 0x3E, 0x96, 0xFE, 0xE5, 0xDB, 0x14, 0xF8, 0x77, 0x3E, 0x18, 0xAF, 0x14, 0x85, 0x79, 0x13, 0x50, 0x9D, 0xA9, 0x99, 0xB4, 0x6C, 0xDD, 0x3D, 0x4C, 0x16, 0x97, 0x60, 0xC8, 0x3A, 0xD2 }, ++ { 0x40, 0xB9, 0x91, 0x6F, 0x09, 0x3E, 0x02, 0x7A, 0x87, 0x86, 0x64, 0x18, 0x18, 0x92, 0x06, 0x20, 0x47, 0x2F, 0xBC, 0xF6, 0x8F, 0x70, 0x1D, 0x1B, 0x68, 0x06, 0x32, 0xE6, 0x99, 0x6B, 0xDE, 0xD3 }, ++ { 0x24, 0xC4, 0xCB, 0xBA, 0x07, 0x11, 0x98, 0x31, 0xA7, 0x26, 0xB0, 0x53, 0x05, 0xD9, 0x6D, 0xA0, 0x2F, 0xF8, 0xB1, 0x48, 0xF0, 0xDA, 0x44, 0x0F, 0xE2, 0x33, 0xBC, 0xAA, 0x32, 0xC7, 0x2F, 0x6F }, ++ { 0x5D, 0x20, 0x15, 0x10, 0x25, 0x00, 0x20, 0xB7, 0x83, 0x68, 0x96, 0x88, 0xAB, 0xBF, 0x8E, 0xCF, 0x25, 0x94, 0xA9, 0x6A, 0x08, 0xF2, 0xBF, 0xEC, 0x6C, 0xE0, 0x57, 0x44, 0x65, 0xDD, 0xED, 0x71 }, ++ { 0x04, 0x3B, 0x97, 0xE3, 0x36, 0xEE, 0x6F, 0xDB, 0xBE, 0x2B, 0x50, 0xF2, 0x2A, 0xF8, 0x32, 0x75, 0xA4, 0x08, 0x48, 0x05, 0xD2, 0xD5, 0x64, 0x59, 0x62, 0x45, 0x4B, 0x6C, 0x9B, 0x80, 0x53, 0xA0 }, ++ { 0x56, 0x48, 0x35, 0xCB, 0xAE, 0xA7, 0x74, 0x94, 0x85, 0x68, 0xBE, 0x36, 0xCF, 0x52, 0xFC, 0xDD, 0x83, 0x93, 0x4E, 0xB0, 0xA2, 0x75, 0x12, 0xDB, 0xE3, 0xE2, 0xDB, 0x47, 0xB9, 0xE6, 0x63, 0x5A }, ++ { 0xF2, 0x1C, 0x33, 0xF4, 0x7B, 0xDE, 0x40, 0xA2, 0xA1, 0x01, 0xC9, 0xCD, 0xE8, 0x02, 0x7A, 0xAF, 0x61, 0xA3, 0x13, 0x7D, 0xE2, 0x42, 0x2B, 0x30, 0x03, 0x5A, 0x04, 0xC2, 0x70, 0x89, 0x41, 0x83 }, ++ { 0x9D, 0xB0, 0xEF, 0x74, 0xE6, 0x6C, 0xBB, 0x84, 0x2E, 0xB0, 0xE0, 0x73, 0x43, 0xA0, 0x3C, 0x5C, 0x56, 0x7E, 0x37, 0x2B, 0x3F, 0x23, 0xB9, 0x43, 0xC7, 0x88, 0xA4, 0xF2, 0x50, 0xF6, 0x78, 0x91 }, ++ { 0xAB, 0x8D, 0x08, 0x65, 0x5F, 0xF1, 0xD3, 0xFE, 0x87, 0x58, 0xD5, 0x62, 0x23, 0x5F, 0xD2, 0x3E, 0x7C, 0xF9, 0xDC, 0xAA, 0xD6, 0x58, 0x87, 0x2A, 0x49, 0xE5, 0xD3, 0x18, 0x3B, 0x6C, 0xCE, 0xBD }, ++ { 0x6F, 0x27, 0xF7, 0x7E, 0x7B, 0xCF, 0x46, 0xA1, 0xE9, 0x63, 0xAD, 0xE0, 0x30, 0x97, 0x33, 0x54, 0x30, 0x31, 0xDC, 0xCD, 0xD4, 0x7C, 0xAA, 0xC1, 0x74, 0xD7, 0xD2, 0x7C, 0xE8, 0x07, 0x7E, 0x8B }, ++ { 0xE3, 0xCD, 0x54, 0xDA, 0x7E, 0x44, 0x4C, 0xAA, 0x62, 0x07, 0x56, 0x95, 0x25, 0xA6, 0x70, 0xEB, 0xAE, 0x12, 0x78, 0xDE, 0x4E, 0x3F, 0xE2, 0x68, 0x4B, 0x3E, 0x33, 0xF5, 0xEF, 0x90, 0xCC, 0x1B }, ++ { 0xB2, 0xC3, 0xE3, 0x3A, 0x51, 0xD2, 0x2C, 0x4C, 0x08, 0xFC, 0x09, 0x89, 0xC8, 0x73, 0xC9, 0xCC, 0x41, 0x50, 0x57, 0x9B, 0x1E, 0x61, 0x63, 0xFA, 0x69, 0x4A, 0xD5, 0x1D, 0x53, 0xD7, 0x12, 0xDC }, ++ { 0xBE, 0x7F, 0xDA, 0x98, 0x3E, 0x13, 0x18, 0x9B, 0x4C, 0x77, 0xE0, 0xA8, 0x09, 0x20, 0xB6, 0xE0, 0xE0, 0xEA, 0x80, 0xC3, 0xB8, 0x4D, 0xBE, 0x7E, 0x71, 0x17, 0xD2, 0x53, 0xF4, 0x81, 0x12, 0xF4 }, ++ { 0xB6, 0x00, 0x8C, 0x28, 0xFA, 0xE0, 0x8A, 0xA4, 0x27, 0xE5, 0xBD, 0x3A, 0xAD, 0x36, 0xF1, 0x00, 0x21, 0xF1, 0x6C, 0x77, 0xCF, 0xEA, 0xBE, 0xD0, 0x7F, 0x97, 0xCC, 0x7D, 0xC1, 0xF1, 0x28, 0x4A }, ++ { 0x6E, 0x4E, 0x67, 0x60, 0xC5, 0x38, 0xF2, 0xE9, 0x7B, 0x3A, 0xDB, 0xFB, 0xBC, 0xDE, 0x57, 0xF8, 0x96, 0x6B, 0x7E, 0xA8, 0xFC, 0xB5, 0xBF, 0x7E, 0xFE, 0xC9, 0x13, 0xFD, 0x2A, 0x2B, 0x0C, 0x55 }, ++ { 0x4A, 0xE5, 0x1F, 0xD1, 0x83, 0x4A, 0xA5, 0xBD, 0x9A, 0x6F, 0x7E, 0xC3, 0x9F, 0xC6, 0x63, 0x33, 0x8D, 0xC5, 0xD2, 0xE2, 0x07, 0x61, 0x56, 0x6D, 0x90, 0xCC, 0x68, 0xB1, 0xCB, 0x87, 0x5E, 0xD8 }, ++ { 0xB6, 0x73, 0xAA, 0xD7, 0x5A, 0xB1, 0xFD, 0xB5, 0x40, 0x1A, 0xBF, 0xA1, 0xBF, 0x89, 0xF3, 0xAD, 0xD2, 0xEB, 0xC4, 0x68, 0xDF, 0x36, 0x24, 0xA4, 0x78, 0xF4, 0xFE, 0x85, 0x9D, 0x8D, 0x55, 0xE2 }, ++ { 0x13, 0xC9, 0x47, 0x1A, 0x98, 0x55, 0x91, 0x35, 0x39, 0x83, 0x66, 0x60, 0x39, 0x8D, 0xA0, 0xF3, 0xF9, 0x9A, 0xDA, 0x08, 0x47, 0x9C, 0x69, 0xD1, 0xB7, 0xFC, 0xAA, 0x34, 0x61, 0xDD, 0x7E, 0x59 }, ++ { 0x2C, 0x11, 0xF4, 0xA7, 0xF9, 0x9A, 0x1D, 0x23, 0xA5, 0x8B, 0xB6, 0x36, 0x35, 0x0F, 0xE8, 0x49, 0xF2, 0x9C, 0xBA, 0xC1, 0xB2, 0xA1, 0x11, 0x2D, 0x9F, 0x1E, 0xD5, 0xBC, 0x5B, 0x31, 0x3C, 0xCD }, ++ { 0xC7, 0xD3, 0xC0, 0x70, 0x6B, 0x11, 0xAE, 0x74, 0x1C, 0x05, 0xA1, 0xEF, 0x15, 0x0D, 0xD6, 0x5B, 0x54, 0x94, 0xD6, 0xD5, 0x4C, 0x9A, 0x86, 0xE2, 0x61, 0x78, 0x54, 0xE6, 0xAE, 0xEE, 0xBB, 0xD9 }, ++ { 0x19, 0x4E, 0x10, 0xC9, 0x38, 0x93, 0xAF, 0xA0, 0x64, 0xC3, 0xAC, 0x04, 0xC0, 0xDD, 0x80, 0x8D, 0x79, 0x1C, 0x3D, 0x4B, 0x75, 0x56, 0xE8, 0x9D, 0x8D, 0x9C, 0xB2, 0x25, 0xC4, 0xB3, 0x33, 0x39 }, ++ { 0x6F, 0xC4, 0x98, 0x8B, 0x8F, 0x78, 0x54, 0x6B, 0x16, 0x88, 0x99, 0x18, 0x45, 0x90, 0x8F, 0x13, 0x4B, 0x6A, 0x48, 0x2E, 0x69, 0x94, 0xB3, 0xD4, 0x83, 0x17, 0xBF, 0x08, 0xDB, 0x29, 0x21, 0x85 }, ++ { 0x56, 0x65, 0xBE, 0xB8, 0xB0, 0x95, 0x55, 0x25, 0x81, 0x3B, 0x59, 0x81, 0xCD, 0x14, 0x2E, 0xD4, 0xD0, 0x3F, 0xBA, 0x38, 0xA6, 0xF3, 0xE5, 0xAD, 0x26, 0x8E, 0x0C, 0xC2, 0x70, 0xD1, 0xCD, 0x11 }, ++ { 0xB8, 0x83, 0xD6, 0x8F, 0x5F, 0xE5, 0x19, 0x36, 0x43, 0x1B, 0xA4, 0x25, 0x67, 0x38, 0x05, 0x3B, 0x1D, 0x04, 0x26, 0xD4, 0xCB, 0x64, 0xB1, 0x6E, 0x83, 0xBA, 0xDC, 0x5E, 0x9F, 0xBE, 0x3B, 0x81 }, ++ { 0x53, 0xE7, 0xB2, 0x7E, 0xA5, 0x9C, 0x2F, 0x6D, 0xBB, 0x50, 0x76, 0x9E, 0x43, 0x55, 0x4D, 0xF3, 0x5A, 0xF8, 0x9F, 0x48, 0x22, 0xD0, 0x46, 0x6B, 0x00, 0x7D, 0xD6, 0xF6, 0xDE, 0xAF, 0xFF, 0x02 }, ++ { 0x1F, 0x1A, 0x02, 0x29, 0xD4, 0x64, 0x0F, 0x01, 0x90, 0x15, 0x88, 0xD9, 0xDE, 0xC2, 0x2D, 0x13, 0xFC, 0x3E, 0xB3, 0x4A, 0x61, 0xB3, 0x29, 0x38, 0xEF, 0xBF, 0x53, 0x34, 0xB2, 0x80, 0x0A, 0xFA }, ++ { 0xC2, 0xB4, 0x05, 0xAF, 0xA0, 0xFA, 0x66, 0x68, 0x85, 0x2A, 0xEE, 0x4D, 0x88, 0x04, 0x08, 0x53, 0xFA, 0xB8, 0x00, 0xE7, 0x2B, 0x57, 0x58, 0x14, 0x18, 0xE5, 0x50, 0x6F, 0x21, 0x4C, 0x7D, 0x1F }, ++ { 0xC0, 0x8A, 0xA1, 0xC2, 0x86, 0xD7, 0x09, 0xFD, 0xC7, 0x47, 0x37, 0x44, 0x97, 0x71, 0x88, 0xC8, 0x95, 0xBA, 0x01, 0x10, 0x14, 0x24, 0x7E, 0x4E, 0xFA, 0x8D, 0x07, 0xE7, 0x8F, 0xEC, 0x69, 0x5C }, ++ { 0xF0, 0x3F, 0x57, 0x89, 0xD3, 0x33, 0x6B, 0x80, 0xD0, 0x02, 0xD5, 0x9F, 0xDF, 0x91, 0x8B, 0xDB, 0x77, 0x5B, 0x00, 0x95, 0x6E, 0xD5, 0x52, 0x8E, 0x86, 0xAA, 0x99, 0x4A, 0xCB, 0x38, 0xFE, 0x2D } ++}; ++ ++static const u8 blake2s_keyed_testvecs[][BLAKE2S_OUTBYTES] = { ++ { 0x48, 0xA8, 0x99, 0x7D, 0xA4, 0x07, 0x87, 0x6B, 0x3D, 0x79, 0xC0, 0xD9, 0x23, 0x25, 0xAD, 0x3B, 0x89, 0xCB, 0xB7, 0x54, 0xD8, 0x6A, 0xB7, 0x1A, 0xEE, 0x04, 0x7A, 0xD3, 0x45, 0xFD, 0x2C, 0x49 }, ++ { 0x40, 0xD1, 0x5F, 0xEE, 0x7C, 0x32, 0x88, 0x30, 0x16, 0x6A, 0xC3, 0xF9, 0x18, 0x65, 0x0F, 0x80, 0x7E, 0x7E, 0x01, 0xE1, 0x77, 0x25, 0x8C, 0xDC, 0x0A, 0x39, 0xB1, 0x1F, 0x59, 0x80, 0x66, 0xF1 }, ++ { 0x6B, 0xB7, 0x13, 0x00, 0x64, 0x4C, 0xD3, 0x99, 0x1B, 0x26, 0xCC, 0xD4, 0xD2, 0x74, 0xAC, 0xD1, 0xAD, 0xEA, 0xB8, 0xB1, 0xD7, 0x91, 0x45, 0x46, 0xC1, 0x19, 0x8B, 0xBE, 0x9F, 0xC9, 0xD8, 0x03 }, ++ { 0x1D, 0x22, 0x0D, 0xBE, 0x2E, 0xE1, 0x34, 0x66, 0x1F, 0xDF, 0x6D, 0x9E, 0x74, 0xB4, 0x17, 0x04, 0x71, 0x05, 0x56, 0xF2, 0xF6, 0xE5, 0xA0, 0x91, 0xB2, 0x27, 0x69, 0x74, 0x45, 0xDB, 0xEA, 0x6B }, ++ { 0xF6, 0xC3, 0xFB, 0xAD, 0xB4, 0xCC, 0x68, 0x7A, 0x00, 0x64, 0xA5, 0xBE, 0x6E, 0x79, 0x1B, 0xEC, 0x63, 0xB8, 0x68, 0xAD, 0x62, 0xFB, 0xA6, 0x1B, 0x37, 0x57, 0xEF, 0x9C, 0xA5, 0x2E, 0x05, 0xB2 }, ++ { 0x49, 0xC1, 0xF2, 0x11, 0x88, 0xDF, 0xD7, 0x69, 0xAE, 0xA0, 0xE9, 0x11, 0xDD, 0x6B, 0x41, 0xF1, 0x4D, 0xAB, 0x10, 0x9D, 0x2B, 0x85, 0x97, 0x7A, 0xA3, 0x08, 0x8B, 0x5C, 0x70, 0x7E, 0x85, 0x98 }, ++ { 0xFD, 0xD8, 0x99, 0x3D, 0xCD, 0x43, 0xF6, 0x96, 0xD4, 0x4F, 0x3C, 0xEA, 0x0F, 0xF3, 0x53, 0x45, 0x23, 0x4E, 0xC8, 0xEE, 0x08, 0x3E, 0xB3, 0xCA, 0xDA, 0x01, 0x7C, 0x7F, 0x78, 0xC1, 0x71, 0x43 }, ++ { 0xE6, 0xC8, 0x12, 0x56, 0x37, 0x43, 0x8D, 0x09, 0x05, 0xB7, 0x49, 0xF4, 0x65, 0x60, 0xAC, 0x89, 0xFD, 0x47, 0x1C, 0xF8, 0x69, 0x2E, 0x28, 0xFA, 0xB9, 0x82, 0xF7, 0x3F, 0x01, 0x9B, 0x83, 0xA9 }, ++ { 0x19, 0xFC, 0x8C, 0xA6, 0x97, 0x9D, 0x60, 0xE6, 0xED, 0xD3, 0xB4, 0x54, 0x1E, 0x2F, 0x96, 0x7C, 0xED, 0x74, 0x0D, 0xF6, 0xEC, 0x1E, 0xAE, 0xBB, 0xFE, 0x81, 0x38, 0x32, 0xE9, 0x6B, 0x29, 0x74 }, ++ { 0xA6, 0xAD, 0x77, 0x7C, 0xE8, 0x81, 0xB5, 0x2B, 0xB5, 0xA4, 0x42, 0x1A, 0xB6, 0xCD, 0xD2, 0xDF, 0xBA, 0x13, 0xE9, 0x63, 0x65, 0x2D, 0x4D, 0x6D, 0x12, 0x2A, 0xEE, 0x46, 0x54, 0x8C, 0x14, 0xA7 }, ++ { 0xF5, 0xC4, 0xB2, 0xBA, 0x1A, 0x00, 0x78, 0x1B, 0x13, 0xAB, 0xA0, 0x42, 0x52, 0x42, 0xC6, 0x9C, 0xB1, 0x55, 0x2F, 0x3F, 0x71, 0xA9, 0xA3, 0xBB, 0x22, 0xB4, 0xA6, 0xB4, 0x27, 0x7B, 0x46, 0xDD }, ++ { 0xE3, 0x3C, 0x4C, 0x9B, 0xD0, 0xCC, 0x7E, 0x45, 0xC8, 0x0E, 0x65, 0xC7, 0x7F, 0xA5, 0x99, 0x7F, 0xEC, 0x70, 0x02, 0x73, 0x85, 0x41, 0x50, 0x9E, 0x68, 0xA9, 0x42, 0x38, 0x91, 0xE8, 0x22, 0xA3 }, ++ { 0xFB, 0xA1, 0x61, 0x69, 0xB2, 0xC3, 0xEE, 0x10, 0x5B, 0xE6, 0xE1, 0xE6, 0x50, 0xE5, 0xCB, 0xF4, 0x07, 0x46, 0xB6, 0x75, 0x3D, 0x03, 0x6A, 0xB5, 0x51, 0x79, 0x01, 0x4A, 0xD7, 0xEF, 0x66, 0x51 }, ++ { 0xF5, 0xC4, 0xBE, 0xC6, 0xD6, 0x2F, 0xC6, 0x08, 0xBF, 0x41, 0xCC, 0x11, 0x5F, 0x16, 0xD6, 0x1C, 0x7E, 0xFD, 0x3F, 0xF6, 0xC6, 0x56, 0x92, 0xBB, 0xE0, 0xAF, 0xFF, 0xB1, 0xFE, 0xDE, 0x74, 0x75 }, ++ { 0xA4, 0x86, 0x2E, 0x76, 0xDB, 0x84, 0x7F, 0x05, 0xBA, 0x17, 0xED, 0xE5, 0xDA, 0x4E, 0x7F, 0x91, 0xB5, 0x92, 0x5C, 0xF1, 0xAD, 0x4B, 0xA1, 0x27, 0x32, 0xC3, 0x99, 0x57, 0x42, 0xA5, 0xCD, 0x6E }, ++ { 0x65, 0xF4, 0xB8, 0x60, 0xCD, 0x15, 0xB3, 0x8E, 0xF8, 0x14, 0xA1, 0xA8, 0x04, 0x31, 0x4A, 0x55, 0xBE, 0x95, 0x3C, 0xAA, 0x65, 0xFD, 0x75, 0x8A, 0xD9, 0x89, 0xFF, 0x34, 0xA4, 0x1C, 0x1E, 0xEA }, ++ { 0x19, 0xBA, 0x23, 0x4F, 0x0A, 0x4F, 0x38, 0x63, 0x7D, 0x18, 0x39, 0xF9, 0xD9, 0xF7, 0x6A, 0xD9, 0x1C, 0x85, 0x22, 0x30, 0x71, 0x43, 0xC9, 0x7D, 0x5F, 0x93, 0xF6, 0x92, 0x74, 0xCE, 0xC9, 0xA7 }, ++ { 0x1A, 0x67, 0x18, 0x6C, 0xA4, 0xA5, 0xCB, 0x8E, 0x65, 0xFC, 0xA0, 0xE2, 0xEC, 0xBC, 0x5D, 0xDC, 0x14, 0xAE, 0x38, 0x1B, 0xB8, 0xBF, 0xFE, 0xB9, 0xE0, 0xA1, 0x03, 0x44, 0x9E, 0x3E, 0xF0, 0x3C }, ++ { 0xAF, 0xBE, 0xA3, 0x17, 0xB5, 0xA2, 0xE8, 0x9C, 0x0B, 0xD9, 0x0C, 0xCF, 0x5D, 0x7F, 0xD0, 0xED, 0x57, 0xFE, 0x58, 0x5E, 0x4B, 0xE3, 0x27, 0x1B, 0x0A, 0x6B, 0xF0, 0xF5, 0x78, 0x6B, 0x0F, 0x26 }, ++ { 0xF1, 0xB0, 0x15, 0x58, 0xCE, 0x54, 0x12, 0x62, 0xF5, 0xEC, 0x34, 0x29, 0x9D, 0x6F, 0xB4, 0x09, 0x00, 0x09, 0xE3, 0x43, 0x4B, 0xE2, 0xF4, 0x91, 0x05, 0xCF, 0x46, 0xAF, 0x4D, 0x2D, 0x41, 0x24 }, ++ { 0x13, 0xA0, 0xA0, 0xC8, 0x63, 0x35, 0x63, 0x5E, 0xAA, 0x74, 0xCA, 0x2D, 0x5D, 0x48, 0x8C, 0x79, 0x7B, 0xBB, 0x4F, 0x47, 0xDC, 0x07, 0x10, 0x50, 0x15, 0xED, 0x6A, 0x1F, 0x33, 0x09, 0xEF, 0xCE }, ++ { 0x15, 0x80, 0xAF, 0xEE, 0xBE, 0xBB, 0x34, 0x6F, 0x94, 0xD5, 0x9F, 0xE6, 0x2D, 0xA0, 0xB7, 0x92, 0x37, 0xEA, 0xD7, 0xB1, 0x49, 0x1F, 0x56, 0x67, 0xA9, 0x0E, 0x45, 0xED, 0xF6, 0xCA, 0x8B, 0x03 }, ++ { 0x20, 0xBE, 0x1A, 0x87, 0x5B, 0x38, 0xC5, 0x73, 0xDD, 0x7F, 0xAA, 0xA0, 0xDE, 0x48, 0x9D, 0x65, 0x5C, 0x11, 0xEF, 0xB6, 0xA5, 0x52, 0x69, 0x8E, 0x07, 0xA2, 0xD3, 0x31, 0xB5, 0xF6, 0x55, 0xC3 }, ++ { 0xBE, 0x1F, 0xE3, 0xC4, 0xC0, 0x40, 0x18, 0xC5, 0x4C, 0x4A, 0x0F, 0x6B, 0x9A, 0x2E, 0xD3, 0xC5, 0x3A, 0xBE, 0x3A, 0x9F, 0x76, 0xB4, 0xD2, 0x6D, 0xE5, 0x6F, 0xC9, 0xAE, 0x95, 0x05, 0x9A, 0x99 }, ++ { 0xE3, 0xE3, 0xAC, 0xE5, 0x37, 0xEB, 0x3E, 0xDD, 0x84, 0x63, 0xD9, 0xAD, 0x35, 0x82, 0xE1, 0x3C, 0xF8, 0x65, 0x33, 0xFF, 0xDE, 0x43, 0xD6, 0x68, 0xDD, 0x2E, 0x93, 0xBB, 0xDB, 0xD7, 0x19, 0x5A }, ++ { 0x11, 0x0C, 0x50, 0xC0, 0xBF, 0x2C, 0x6E, 0x7A, 0xEB, 0x7E, 0x43, 0x5D, 0x92, 0xD1, 0x32, 0xAB, 0x66, 0x55, 0x16, 0x8E, 0x78, 0xA2, 0xDE, 0xCD, 0xEC, 0x33, 0x30, 0x77, 0x76, 0x84, 0xD9, 0xC1 }, ++ { 0xE9, 0xBA, 0x8F, 0x50, 0x5C, 0x9C, 0x80, 0xC0, 0x86, 0x66, 0xA7, 0x01, 0xF3, 0x36, 0x7E, 0x6C, 0xC6, 0x65, 0xF3, 0x4B, 0x22, 0xE7, 0x3C, 0x3C, 0x04, 0x17, 0xEB, 0x1C, 0x22, 0x06, 0x08, 0x2F }, ++ { 0x26, 0xCD, 0x66, 0xFC, 0xA0, 0x23, 0x79, 0xC7, 0x6D, 0xF1, 0x23, 0x17, 0x05, 0x2B, 0xCA, 0xFD, 0x6C, 0xD8, 0xC3, 0xA7, 0xB8, 0x90, 0xD8, 0x05, 0xF3, 0x6C, 0x49, 0x98, 0x97, 0x82, 0x43, 0x3A }, ++ { 0x21, 0x3F, 0x35, 0x96, 0xD6, 0xE3, 0xA5, 0xD0, 0xE9, 0x93, 0x2C, 0xD2, 0x15, 0x91, 0x46, 0x01, 0x5E, 0x2A, 0xBC, 0x94, 0x9F, 0x47, 0x29, 0xEE, 0x26, 0x32, 0xFE, 0x1E, 0xDB, 0x78, 0xD3, 0x37 }, ++ { 0x10, 0x15, 0xD7, 0x01, 0x08, 0xE0, 0x3B, 0xE1, 0xC7, 0x02, 0xFE, 0x97, 0x25, 0x36, 0x07, 0xD1, 0x4A, 0xEE, 0x59, 0x1F, 0x24, 0x13, 0xEA, 0x67, 0x87, 0x42, 0x7B, 0x64, 0x59, 0xFF, 0x21, 0x9A }, ++ { 0x3C, 0xA9, 0x89, 0xDE, 0x10, 0xCF, 0xE6, 0x09, 0x90, 0x94, 0x72, 0xC8, 0xD3, 0x56, 0x10, 0x80, 0x5B, 0x2F, 0x97, 0x77, 0x34, 0xCF, 0x65, 0x2C, 0xC6, 0x4B, 0x3B, 0xFC, 0x88, 0x2D, 0x5D, 0x89 }, ++ { 0xB6, 0x15, 0x6F, 0x72, 0xD3, 0x80, 0xEE, 0x9E, 0xA6, 0xAC, 0xD1, 0x90, 0x46, 0x4F, 0x23, 0x07, 0xA5, 0xC1, 0x79, 0xEF, 0x01, 0xFD, 0x71, 0xF9, 0x9F, 0x2D, 0x0F, 0x7A, 0x57, 0x36, 0x0A, 0xEA }, ++ { 0xC0, 0x3B, 0xC6, 0x42, 0xB2, 0x09, 0x59, 0xCB, 0xE1, 0x33, 0xA0, 0x30, 0x3E, 0x0C, 0x1A, 0xBF, 0xF3, 0xE3, 0x1E, 0xC8, 0xE1, 0xA3, 0x28, 0xEC, 0x85, 0x65, 0xC3, 0x6D, 0xEC, 0xFF, 0x52, 0x65 }, ++ { 0x2C, 0x3E, 0x08, 0x17, 0x6F, 0x76, 0x0C, 0x62, 0x64, 0xC3, 0xA2, 0xCD, 0x66, 0xFE, 0xC6, 0xC3, 0xD7, 0x8D, 0xE4, 0x3F, 0xC1, 0x92, 0x45, 0x7B, 0x2A, 0x4A, 0x66, 0x0A, 0x1E, 0x0E, 0xB2, 0x2B }, ++ { 0xF7, 0x38, 0xC0, 0x2F, 0x3C, 0x1B, 0x19, 0x0C, 0x51, 0x2B, 0x1A, 0x32, 0xDE, 0xAB, 0xF3, 0x53, 0x72, 0x8E, 0x0E, 0x9A, 0xB0, 0x34, 0x49, 0x0E, 0x3C, 0x34, 0x09, 0x94, 0x6A, 0x97, 0xAE, 0xEC }, ++ { 0x8B, 0x18, 0x80, 0xDF, 0x30, 0x1C, 0xC9, 0x63, 0x41, 0x88, 0x11, 0x08, 0x89, 0x64, 0x83, 0x92, 0x87, 0xFF, 0x7F, 0xE3, 0x1C, 0x49, 0xEA, 0x6E, 0xBD, 0x9E, 0x48, 0xBD, 0xEE, 0xE4, 0x97, 0xC5 }, ++ { 0x1E, 0x75, 0xCB, 0x21, 0xC6, 0x09, 0x89, 0x02, 0x03, 0x75, 0xF1, 0xA7, 0xA2, 0x42, 0x83, 0x9F, 0x0B, 0x0B, 0x68, 0x97, 0x3A, 0x4C, 0x2A, 0x05, 0xCF, 0x75, 0x55, 0xED, 0x5A, 0xAE, 0xC4, 0xC1 }, ++ { 0x62, 0xBF, 0x8A, 0x9C, 0x32, 0xA5, 0xBC, 0xCF, 0x29, 0x0B, 0x6C, 0x47, 0x4D, 0x75, 0xB2, 0xA2, 0xA4, 0x09, 0x3F, 0x1A, 0x9E, 0x27, 0x13, 0x94, 0x33, 0xA8, 0xF2, 0xB3, 0xBC, 0xE7, 0xB8, 0xD7 }, ++ { 0x16, 0x6C, 0x83, 0x50, 0xD3, 0x17, 0x3B, 0x5E, 0x70, 0x2B, 0x78, 0x3D, 0xFD, 0x33, 0xC6, 0x6E, 0xE0, 0x43, 0x27, 0x42, 0xE9, 0xB9, 0x2B, 0x99, 0x7F, 0xD2, 0x3C, 0x60, 0xDC, 0x67, 0x56, 0xCA }, ++ { 0x04, 0x4A, 0x14, 0xD8, 0x22, 0xA9, 0x0C, 0xAC, 0xF2, 0xF5, 0xA1, 0x01, 0x42, 0x8A, 0xDC, 0x8F, 0x41, 0x09, 0x38, 0x6C, 0xCB, 0x15, 0x8B, 0xF9, 0x05, 0xC8, 0x61, 0x8B, 0x8E, 0xE2, 0x4E, 0xC3 }, ++ { 0x38, 0x7D, 0x39, 0x7E, 0xA4, 0x3A, 0x99, 0x4B, 0xE8, 0x4D, 0x2D, 0x54, 0x4A, 0xFB, 0xE4, 0x81, 0xA2, 0x00, 0x0F, 0x55, 0x25, 0x26, 0x96, 0xBB, 0xA2, 0xC5, 0x0C, 0x8E, 0xBD, 0x10, 0x13, 0x47 }, ++ { 0x56, 0xF8, 0xCC, 0xF1, 0xF8, 0x64, 0x09, 0xB4, 0x6C, 0xE3, 0x61, 0x66, 0xAE, 0x91, 0x65, 0x13, 0x84, 0x41, 0x57, 0x75, 0x89, 0xDB, 0x08, 0xCB, 0xC5, 0xF6, 0x6C, 0xA2, 0x97, 0x43, 0xB9, 0xFD }, ++ { 0x97, 0x06, 0xC0, 0x92, 0xB0, 0x4D, 0x91, 0xF5, 0x3D, 0xFF, 0x91, 0xFA, 0x37, 0xB7, 0x49, 0x3D, 0x28, 0xB5, 0x76, 0xB5, 0xD7, 0x10, 0x46, 0x9D, 0xF7, 0x94, 0x01, 0x66, 0x22, 0x36, 0xFC, 0x03 }, ++ { 0x87, 0x79, 0x68, 0x68, 0x6C, 0x06, 0x8C, 0xE2, 0xF7, 0xE2, 0xAD, 0xCF, 0xF6, 0x8B, 0xF8, 0x74, 0x8E, 0xDF, 0x3C, 0xF8, 0x62, 0xCF, 0xB4, 0xD3, 0x94, 0x7A, 0x31, 0x06, 0x95, 0x80, 0x54, 0xE3 }, ++ { 0x88, 0x17, 0xE5, 0x71, 0x98, 0x79, 0xAC, 0xF7, 0x02, 0x47, 0x87, 0xEC, 0xCD, 0xB2, 0x71, 0x03, 0x55, 0x66, 0xCF, 0xA3, 0x33, 0xE0, 0x49, 0x40, 0x7C, 0x01, 0x78, 0xCC, 0xC5, 0x7A, 0x5B, 0x9F }, ++ { 0x89, 0x38, 0x24, 0x9E, 0x4B, 0x50, 0xCA, 0xDA, 0xCC, 0xDF, 0x5B, 0x18, 0x62, 0x13, 0x26, 0xCB, 0xB1, 0x52, 0x53, 0xE3, 0x3A, 0x20, 0xF5, 0x63, 0x6E, 0x99, 0x5D, 0x72, 0x47, 0x8D, 0xE4, 0x72 }, ++ { 0xF1, 0x64, 0xAB, 0xBA, 0x49, 0x63, 0xA4, 0x4D, 0x10, 0x72, 0x57, 0xE3, 0x23, 0x2D, 0x90, 0xAC, 0xA5, 0xE6, 0x6A, 0x14, 0x08, 0x24, 0x8C, 0x51, 0x74, 0x1E, 0x99, 0x1D, 0xB5, 0x22, 0x77, 0x56 }, ++ { 0xD0, 0x55, 0x63, 0xE2, 0xB1, 0xCB, 0xA0, 0xC4, 0xA2, 0xA1, 0xE8, 0xBD, 0xE3, 0xA1, 0xA0, 0xD9, 0xF5, 0xB4, 0x0C, 0x85, 0xA0, 0x70, 0xD6, 0xF5, 0xFB, 0x21, 0x06, 0x6E, 0xAD, 0x5D, 0x06, 0x01 }, ++ { 0x03, 0xFB, 0xB1, 0x63, 0x84, 0xF0, 0xA3, 0x86, 0x6F, 0x4C, 0x31, 0x17, 0x87, 0x76, 0x66, 0xEF, 0xBF, 0x12, 0x45, 0x97, 0x56, 0x4B, 0x29, 0x3D, 0x4A, 0xAB, 0x0D, 0x26, 0x9F, 0xAB, 0xDD, 0xFA }, ++ { 0x5F, 0xA8, 0x48, 0x6A, 0xC0, 0xE5, 0x29, 0x64, 0xD1, 0x88, 0x1B, 0xBE, 0x33, 0x8E, 0xB5, 0x4B, 0xE2, 0xF7, 0x19, 0x54, 0x92, 0x24, 0x89, 0x20, 0x57, 0xB4, 0xDA, 0x04, 0xBA, 0x8B, 0x34, 0x75 }, ++ { 0xCD, 0xFA, 0xBC, 0xEE, 0x46, 0x91, 0x11, 0x11, 0x23, 0x6A, 0x31, 0x70, 0x8B, 0x25, 0x39, 0xD7, 0x1F, 0xC2, 0x11, 0xD9, 0xB0, 0x9C, 0x0D, 0x85, 0x30, 0xA1, 0x1E, 0x1D, 0xBF, 0x6E, 0xED, 0x01 }, ++ { 0x4F, 0x82, 0xDE, 0x03, 0xB9, 0x50, 0x47, 0x93, 0xB8, 0x2A, 0x07, 0xA0, 0xBD, 0xCD, 0xFF, 0x31, 0x4D, 0x75, 0x9E, 0x7B, 0x62, 0xD2, 0x6B, 0x78, 0x49, 0x46, 0xB0, 0xD3, 0x6F, 0x91, 0x6F, 0x52 }, ++ { 0x25, 0x9E, 0xC7, 0xF1, 0x73, 0xBC, 0xC7, 0x6A, 0x09, 0x94, 0xC9, 0x67, 0xB4, 0xF5, 0xF0, 0x24, 0xC5, 0x60, 0x57, 0xFB, 0x79, 0xC9, 0x65, 0xC4, 0xFA, 0xE4, 0x18, 0x75, 0xF0, 0x6A, 0x0E, 0x4C }, ++ { 0x19, 0x3C, 0xC8, 0xE7, 0xC3, 0xE0, 0x8B, 0xB3, 0x0F, 0x54, 0x37, 0xAA, 0x27, 0xAD, 0xE1, 0xF1, 0x42, 0x36, 0x9B, 0x24, 0x6A, 0x67, 0x5B, 0x23, 0x83, 0xE6, 0xDA, 0x9B, 0x49, 0xA9, 0x80, 0x9E }, ++ { 0x5C, 0x10, 0x89, 0x6F, 0x0E, 0x28, 0x56, 0xB2, 0xA2, 0xEE, 0xE0, 0xFE, 0x4A, 0x2C, 0x16, 0x33, 0x56, 0x5D, 0x18, 0xF0, 0xE9, 0x3E, 0x1F, 0xAB, 0x26, 0xC3, 0x73, 0xE8, 0xF8, 0x29, 0x65, 0x4D }, ++ { 0xF1, 0x60, 0x12, 0xD9, 0x3F, 0x28, 0x85, 0x1A, 0x1E, 0xB9, 0x89, 0xF5, 0xD0, 0xB4, 0x3F, 0x3F, 0x39, 0xCA, 0x73, 0xC9, 0xA6, 0x2D, 0x51, 0x81, 0xBF, 0xF2, 0x37, 0x53, 0x6B, 0xD3, 0x48, 0xC3 }, ++ { 0x29, 0x66, 0xB3, 0xCF, 0xAE, 0x1E, 0x44, 0xEA, 0x99, 0x6D, 0xC5, 0xD6, 0x86, 0xCF, 0x25, 0xFA, 0x05, 0x3F, 0xB6, 0xF6, 0x72, 0x01, 0xB9, 0xE4, 0x6E, 0xAD, 0xE8, 0x5D, 0x0A, 0xD6, 0xB8, 0x06 }, ++ { 0xDD, 0xB8, 0x78, 0x24, 0x85, 0xE9, 0x00, 0xBC, 0x60, 0xBC, 0xF4, 0xC3, 0x3A, 0x6F, 0xD5, 0x85, 0x68, 0x0C, 0xC6, 0x83, 0xD5, 0x16, 0xEF, 0xA0, 0x3E, 0xB9, 0x98, 0x5F, 0xAD, 0x87, 0x15, 0xFB }, ++ { 0x4C, 0x4D, 0x6E, 0x71, 0xAE, 0xA0, 0x57, 0x86, 0x41, 0x31, 0x48, 0xFC, 0x7A, 0x78, 0x6B, 0x0E, 0xCA, 0xF5, 0x82, 0xCF, 0xF1, 0x20, 0x9F, 0x5A, 0x80, 0x9F, 0xBA, 0x85, 0x04, 0xCE, 0x66, 0x2C }, ++ { 0xFB, 0x4C, 0x5E, 0x86, 0xD7, 0xB2, 0x22, 0x9B, 0x99, 0xB8, 0xBA, 0x6D, 0x94, 0xC2, 0x47, 0xEF, 0x96, 0x4A, 0xA3, 0xA2, 0xBA, 0xE8, 0xED, 0xC7, 0x75, 0x69, 0xF2, 0x8D, 0xBB, 0xFF, 0x2D, 0x4E }, ++ { 0xE9, 0x4F, 0x52, 0x6D, 0xE9, 0x01, 0x96, 0x33, 0xEC, 0xD5, 0x4A, 0xC6, 0x12, 0x0F, 0x23, 0x95, 0x8D, 0x77, 0x18, 0xF1, 0xE7, 0x71, 0x7B, 0xF3, 0x29, 0x21, 0x1A, 0x4F, 0xAE, 0xED, 0x4E, 0x6D }, ++ { 0xCB, 0xD6, 0x66, 0x0A, 0x10, 0xDB, 0x3F, 0x23, 0xF7, 0xA0, 0x3D, 0x4B, 0x9D, 0x40, 0x44, 0xC7, 0x93, 0x2B, 0x28, 0x01, 0xAC, 0x89, 0xD6, 0x0B, 0xC9, 0xEB, 0x92, 0xD6, 0x5A, 0x46, 0xC2, 0xA0 }, ++ { 0x88, 0x18, 0xBB, 0xD3, 0xDB, 0x4D, 0xC1, 0x23, 0xB2, 0x5C, 0xBB, 0xA5, 0xF5, 0x4C, 0x2B, 0xC4, 0xB3, 0xFC, 0xF9, 0xBF, 0x7D, 0x7A, 0x77, 0x09, 0xF4, 0xAE, 0x58, 0x8B, 0x26, 0x7C, 0x4E, 0xCE }, ++ { 0xC6, 0x53, 0x82, 0x51, 0x3F, 0x07, 0x46, 0x0D, 0xA3, 0x98, 0x33, 0xCB, 0x66, 0x6C, 0x5E, 0xD8, 0x2E, 0x61, 0xB9, 0xE9, 0x98, 0xF4, 0xB0, 0xC4, 0x28, 0x7C, 0xEE, 0x56, 0xC3, 0xCC, 0x9B, 0xCD }, ++ { 0x89, 0x75, 0xB0, 0x57, 0x7F, 0xD3, 0x55, 0x66, 0xD7, 0x50, 0xB3, 0x62, 0xB0, 0x89, 0x7A, 0x26, 0xC3, 0x99, 0x13, 0x6D, 0xF0, 0x7B, 0xAB, 0xAB, 0xBD, 0xE6, 0x20, 0x3F, 0xF2, 0x95, 0x4E, 0xD4 }, ++ { 0x21, 0xFE, 0x0C, 0xEB, 0x00, 0x52, 0xBE, 0x7F, 0xB0, 0xF0, 0x04, 0x18, 0x7C, 0xAC, 0xD7, 0xDE, 0x67, 0xFA, 0x6E, 0xB0, 0x93, 0x8D, 0x92, 0x76, 0x77, 0xF2, 0x39, 0x8C, 0x13, 0x23, 0x17, 0xA8 }, ++ { 0x2E, 0xF7, 0x3F, 0x3C, 0x26, 0xF1, 0x2D, 0x93, 0x88, 0x9F, 0x3C, 0x78, 0xB6, 0xA6, 0x6C, 0x1D, 0x52, 0xB6, 0x49, 0xDC, 0x9E, 0x85, 0x6E, 0x2C, 0x17, 0x2E, 0xA7, 0xC5, 0x8A, 0xC2, 0xB5, 0xE3 }, ++ { 0x38, 0x8A, 0x3C, 0xD5, 0x6D, 0x73, 0x86, 0x7A, 0xBB, 0x5F, 0x84, 0x01, 0x49, 0x2B, 0x6E, 0x26, 0x81, 0xEB, 0x69, 0x85, 0x1E, 0x76, 0x7F, 0xD8, 0x42, 0x10, 0xA5, 0x60, 0x76, 0xFB, 0x3D, 0xD3 }, ++ { 0xAF, 0x53, 0x3E, 0x02, 0x2F, 0xC9, 0x43, 0x9E, 0x4E, 0x3C, 0xB8, 0x38, 0xEC, 0xD1, 0x86, 0x92, 0x23, 0x2A, 0xDF, 0x6F, 0xE9, 0x83, 0x95, 0x26, 0xD3, 0xC3, 0xDD, 0x1B, 0x71, 0x91, 0x0B, 0x1A }, ++ { 0x75, 0x1C, 0x09, 0xD4, 0x1A, 0x93, 0x43, 0x88, 0x2A, 0x81, 0xCD, 0x13, 0xEE, 0x40, 0x81, 0x8D, 0x12, 0xEB, 0x44, 0xC6, 0xC7, 0xF4, 0x0D, 0xF1, 0x6E, 0x4A, 0xEA, 0x8F, 0xAB, 0x91, 0x97, 0x2A }, ++ { 0x5B, 0x73, 0xDD, 0xB6, 0x8D, 0x9D, 0x2B, 0x0A, 0xA2, 0x65, 0xA0, 0x79, 0x88, 0xD6, 0xB8, 0x8A, 0xE9, 0xAA, 0xC5, 0x82, 0xAF, 0x83, 0x03, 0x2F, 0x8A, 0x9B, 0x21, 0xA2, 0xE1, 0xB7, 0xBF, 0x18 }, ++ { 0x3D, 0xA2, 0x91, 0x26, 0xC7, 0xC5, 0xD7, 0xF4, 0x3E, 0x64, 0x24, 0x2A, 0x79, 0xFE, 0xAA, 0x4E, 0xF3, 0x45, 0x9C, 0xDE, 0xCC, 0xC8, 0x98, 0xED, 0x59, 0xA9, 0x7F, 0x6E, 0xC9, 0x3B, 0x9D, 0xAB }, ++ { 0x56, 0x6D, 0xC9, 0x20, 0x29, 0x3D, 0xA5, 0xCB, 0x4F, 0xE0, 0xAA, 0x8A, 0xBD, 0xA8, 0xBB, 0xF5, 0x6F, 0x55, 0x23, 0x13, 0xBF, 0xF1, 0x90, 0x46, 0x64, 0x1E, 0x36, 0x15, 0xC1, 0xE3, 0xED, 0x3F }, ++ { 0x41, 0x15, 0xBE, 0xA0, 0x2F, 0x73, 0xF9, 0x7F, 0x62, 0x9E, 0x5C, 0x55, 0x90, 0x72, 0x0C, 0x01, 0xE7, 0xE4, 0x49, 0xAE, 0x2A, 0x66, 0x97, 0xD4, 0xD2, 0x78, 0x33, 0x21, 0x30, 0x36, 0x92, 0xF9 }, ++ { 0x4C, 0xE0, 0x8F, 0x47, 0x62, 0x46, 0x8A, 0x76, 0x70, 0x01, 0x21, 0x64, 0x87, 0x8D, 0x68, 0x34, 0x0C, 0x52, 0xA3, 0x5E, 0x66, 0xC1, 0x88, 0x4D, 0x5C, 0x86, 0x48, 0x89, 0xAB, 0xC9, 0x66, 0x77 }, ++ { 0x81, 0xEA, 0x0B, 0x78, 0x04, 0x12, 0x4E, 0x0C, 0x22, 0xEA, 0x5F, 0xC7, 0x11, 0x04, 0xA2, 0xAF, 0xCB, 0x52, 0xA1, 0xFA, 0x81, 0x6F, 0x3E, 0xCB, 0x7D, 0xCB, 0x5D, 0x9D, 0xEA, 0x17, 0x86, 0xD0 }, ++ { 0xFE, 0x36, 0x27, 0x33, 0xB0, 0x5F, 0x6B, 0xED, 0xAF, 0x93, 0x79, 0xD7, 0xF7, 0x93, 0x6E, 0xDE, 0x20, 0x9B, 0x1F, 0x83, 0x23, 0xC3, 0x92, 0x25, 0x49, 0xD9, 0xE7, 0x36, 0x81, 0xB5, 0xDB, 0x7B }, ++ { 0xEF, 0xF3, 0x7D, 0x30, 0xDF, 0xD2, 0x03, 0x59, 0xBE, 0x4E, 0x73, 0xFD, 0xF4, 0x0D, 0x27, 0x73, 0x4B, 0x3D, 0xF9, 0x0A, 0x97, 0xA5, 0x5E, 0xD7, 0x45, 0x29, 0x72, 0x94, 0xCA, 0x85, 0xD0, 0x9F }, ++ { 0x17, 0x2F, 0xFC, 0x67, 0x15, 0x3D, 0x12, 0xE0, 0xCA, 0x76, 0xA8, 0xB6, 0xCD, 0x5D, 0x47, 0x31, 0x88, 0x5B, 0x39, 0xCE, 0x0C, 0xAC, 0x93, 0xA8, 0x97, 0x2A, 0x18, 0x00, 0x6C, 0x8B, 0x8B, 0xAF }, ++ { 0xC4, 0x79, 0x57, 0xF1, 0xCC, 0x88, 0xE8, 0x3E, 0xF9, 0x44, 0x58, 0x39, 0x70, 0x9A, 0x48, 0x0A, 0x03, 0x6B, 0xED, 0x5F, 0x88, 0xAC, 0x0F, 0xCC, 0x8E, 0x1E, 0x70, 0x3F, 0xFA, 0xAC, 0x13, 0x2C }, ++ { 0x30, 0xF3, 0x54, 0x83, 0x70, 0xCF, 0xDC, 0xED, 0xA5, 0xC3, 0x7B, 0x56, 0x9B, 0x61, 0x75, 0xE7, 0x99, 0xEE, 0xF1, 0xA6, 0x2A, 0xAA, 0x94, 0x32, 0x45, 0xAE, 0x76, 0x69, 0xC2, 0x27, 0xA7, 0xB5 }, ++ { 0xC9, 0x5D, 0xCB, 0x3C, 0xF1, 0xF2, 0x7D, 0x0E, 0xEF, 0x2F, 0x25, 0xD2, 0x41, 0x38, 0x70, 0x90, 0x4A, 0x87, 0x7C, 0x4A, 0x56, 0xC2, 0xDE, 0x1E, 0x83, 0xE2, 0xBC, 0x2A, 0xE2, 0xE4, 0x68, 0x21 }, ++ { 0xD5, 0xD0, 0xB5, 0xD7, 0x05, 0x43, 0x4C, 0xD4, 0x6B, 0x18, 0x57, 0x49, 0xF6, 0x6B, 0xFB, 0x58, 0x36, 0xDC, 0xDF, 0x6E, 0xE5, 0x49, 0xA2, 0xB7, 0xA4, 0xAE, 0xE7, 0xF5, 0x80, 0x07, 0xCA, 0xAF }, ++ { 0xBB, 0xC1, 0x24, 0xA7, 0x12, 0xF1, 0x5D, 0x07, 0xC3, 0x00, 0xE0, 0x5B, 0x66, 0x83, 0x89, 0xA4, 0x39, 0xC9, 0x17, 0x77, 0xF7, 0x21, 0xF8, 0x32, 0x0C, 0x1C, 0x90, 0x78, 0x06, 0x6D, 0x2C, 0x7E }, ++ { 0xA4, 0x51, 0xB4, 0x8C, 0x35, 0xA6, 0xC7, 0x85, 0x4C, 0xFA, 0xAE, 0x60, 0x26, 0x2E, 0x76, 0x99, 0x08, 0x16, 0x38, 0x2A, 0xC0, 0x66, 0x7E, 0x5A, 0x5C, 0x9E, 0x1B, 0x46, 0xC4, 0x34, 0x2D, 0xDF }, ++ { 0xB0, 0xD1, 0x50, 0xFB, 0x55, 0xE7, 0x78, 0xD0, 0x11, 0x47, 0xF0, 0xB5, 0xD8, 0x9D, 0x99, 0xEC, 0xB2, 0x0F, 0xF0, 0x7E, 0x5E, 0x67, 0x60, 0xD6, 0xB6, 0x45, 0xEB, 0x5B, 0x65, 0x4C, 0x62, 0x2B }, ++ { 0x34, 0xF7, 0x37, 0xC0, 0xAB, 0x21, 0x99, 0x51, 0xEE, 0xE8, 0x9A, 0x9F, 0x8D, 0xAC, 0x29, 0x9C, 0x9D, 0x4C, 0x38, 0xF3, 0x3F, 0xA4, 0x94, 0xC5, 0xC6, 0xEE, 0xFC, 0x92, 0xB6, 0xDB, 0x08, 0xBC }, ++ { 0x1A, 0x62, 0xCC, 0x3A, 0x00, 0x80, 0x0D, 0xCB, 0xD9, 0x98, 0x91, 0x08, 0x0C, 0x1E, 0x09, 0x84, 0x58, 0x19, 0x3A, 0x8C, 0xC9, 0xF9, 0x70, 0xEA, 0x99, 0xFB, 0xEF, 0xF0, 0x03, 0x18, 0xC2, 0x89 }, ++ { 0xCF, 0xCE, 0x55, 0xEB, 0xAF, 0xC8, 0x40, 0xD7, 0xAE, 0x48, 0x28, 0x1C, 0x7F, 0xD5, 0x7E, 0xC8, 0xB4, 0x82, 0xD4, 0xB7, 0x04, 0x43, 0x74, 0x95, 0x49, 0x5A, 0xC4, 0x14, 0xCF, 0x4A, 0x37, 0x4B }, ++ { 0x67, 0x46, 0xFA, 0xCF, 0x71, 0x14, 0x6D, 0x99, 0x9D, 0xAB, 0xD0, 0x5D, 0x09, 0x3A, 0xE5, 0x86, 0x64, 0x8D, 0x1E, 0xE2, 0x8E, 0x72, 0x61, 0x7B, 0x99, 0xD0, 0xF0, 0x08, 0x6E, 0x1E, 0x45, 0xBF }, ++ { 0x57, 0x1C, 0xED, 0x28, 0x3B, 0x3F, 0x23, 0xB4, 0xE7, 0x50, 0xBF, 0x12, 0xA2, 0xCA, 0xF1, 0x78, 0x18, 0x47, 0xBD, 0x89, 0x0E, 0x43, 0x60, 0x3C, 0xDC, 0x59, 0x76, 0x10, 0x2B, 0x7B, 0xB1, 0x1B }, ++ { 0xCF, 0xCB, 0x76, 0x5B, 0x04, 0x8E, 0x35, 0x02, 0x2C, 0x5D, 0x08, 0x9D, 0x26, 0xE8, 0x5A, 0x36, 0xB0, 0x05, 0xA2, 0xB8, 0x04, 0x93, 0xD0, 0x3A, 0x14, 0x4E, 0x09, 0xF4, 0x09, 0xB6, 0xAF, 0xD1 }, ++ { 0x40, 0x50, 0xC7, 0xA2, 0x77, 0x05, 0xBB, 0x27, 0xF4, 0x20, 0x89, 0xB2, 0x99, 0xF3, 0xCB, 0xE5, 0x05, 0x4E, 0xAD, 0x68, 0x72, 0x7E, 0x8E, 0xF9, 0x31, 0x8C, 0xE6, 0xF2, 0x5C, 0xD6, 0xF3, 0x1D }, ++ { 0x18, 0x40, 0x70, 0xBD, 0x5D, 0x26, 0x5F, 0xBD, 0xC1, 0x42, 0xCD, 0x1C, 0x5C, 0xD0, 0xD7, 0xE4, 0x14, 0xE7, 0x03, 0x69, 0xA2, 0x66, 0xD6, 0x27, 0xC8, 0xFB, 0xA8, 0x4F, 0xA5, 0xE8, 0x4C, 0x34 }, ++ { 0x9E, 0xDD, 0xA9, 0xA4, 0x44, 0x39, 0x02, 0xA9, 0x58, 0x8C, 0x0D, 0x0C, 0xCC, 0x62, 0xB9, 0x30, 0x21, 0x84, 0x79, 0xA6, 0x84, 0x1E, 0x6F, 0xE7, 0xD4, 0x30, 0x03, 0xF0, 0x4B, 0x1F, 0xD6, 0x43 }, ++ { 0xE4, 0x12, 0xFE, 0xEF, 0x79, 0x08, 0x32, 0x4A, 0x6D, 0xA1, 0x84, 0x16, 0x29, 0xF3, 0x5D, 0x3D, 0x35, 0x86, 0x42, 0x01, 0x93, 0x10, 0xEC, 0x57, 0xC6, 0x14, 0x83, 0x6B, 0x63, 0xD3, 0x07, 0x63 }, ++ { 0x1A, 0x2B, 0x8E, 0xDF, 0xF3, 0xF9, 0xAC, 0xC1, 0x55, 0x4F, 0xCB, 0xAE, 0x3C, 0xF1, 0xD6, 0x29, 0x8C, 0x64, 0x62, 0xE2, 0x2E, 0x5E, 0xB0, 0x25, 0x96, 0x84, 0xF8, 0x35, 0x01, 0x2B, 0xD1, 0x3F }, ++ { 0x28, 0x8C, 0x4A, 0xD9, 0xB9, 0x40, 0x97, 0x62, 0xEA, 0x07, 0xC2, 0x4A, 0x41, 0xF0, 0x4F, 0x69, 0xA7, 0xD7, 0x4B, 0xEE, 0x2D, 0x95, 0x43, 0x53, 0x74, 0xBD, 0xE9, 0x46, 0xD7, 0x24, 0x1C, 0x7B }, ++ { 0x80, 0x56, 0x91, 0xBB, 0x28, 0x67, 0x48, 0xCF, 0xB5, 0x91, 0xD3, 0xAE, 0xBE, 0x7E, 0x6F, 0x4E, 0x4D, 0xC6, 0xE2, 0x80, 0x8C, 0x65, 0x14, 0x3C, 0xC0, 0x04, 0xE4, 0xEB, 0x6F, 0xD0, 0x9D, 0x43 }, ++ { 0xD4, 0xAC, 0x8D, 0x3A, 0x0A, 0xFC, 0x6C, 0xFA, 0x7B, 0x46, 0x0A, 0xE3, 0x00, 0x1B, 0xAE, 0xB3, 0x6D, 0xAD, 0xB3, 0x7D, 0xA0, 0x7D, 0x2E, 0x8A, 0xC9, 0x18, 0x22, 0xDF, 0x34, 0x8A, 0xED, 0x3D }, ++ { 0xC3, 0x76, 0x61, 0x70, 0x14, 0xD2, 0x01, 0x58, 0xBC, 0xED, 0x3D, 0x3B, 0xA5, 0x52, 0xB6, 0xEC, 0xCF, 0x84, 0xE6, 0x2A, 0xA3, 0xEB, 0x65, 0x0E, 0x90, 0x02, 0x9C, 0x84, 0xD1, 0x3E, 0xEA, 0x69 }, ++ { 0xC4, 0x1F, 0x09, 0xF4, 0x3C, 0xEC, 0xAE, 0x72, 0x93, 0xD6, 0x00, 0x7C, 0xA0, 0xA3, 0x57, 0x08, 0x7D, 0x5A, 0xE5, 0x9B, 0xE5, 0x00, 0xC1, 0xCD, 0x5B, 0x28, 0x9E, 0xE8, 0x10, 0xC7, 0xB0, 0x82 }, ++ { 0x03, 0xD1, 0xCE, 0xD1, 0xFB, 0xA5, 0xC3, 0x91, 0x55, 0xC4, 0x4B, 0x77, 0x65, 0xCB, 0x76, 0x0C, 0x78, 0x70, 0x8D, 0xCF, 0xC8, 0x0B, 0x0B, 0xD8, 0xAD, 0xE3, 0xA5, 0x6D, 0xA8, 0x83, 0x0B, 0x29 }, ++ { 0x09, 0xBD, 0xE6, 0xF1, 0x52, 0x21, 0x8D, 0xC9, 0x2C, 0x41, 0xD7, 0xF4, 0x53, 0x87, 0xE6, 0x3E, 0x58, 0x69, 0xD8, 0x07, 0xEC, 0x70, 0xB8, 0x21, 0x40, 0x5D, 0xBD, 0x88, 0x4B, 0x7F, 0xCF, 0x4B }, ++ { 0x71, 0xC9, 0x03, 0x6E, 0x18, 0x17, 0x9B, 0x90, 0xB3, 0x7D, 0x39, 0xE9, 0xF0, 0x5E, 0xB8, 0x9C, 0xC5, 0xFC, 0x34, 0x1F, 0xD7, 0xC4, 0x77, 0xD0, 0xD7, 0x49, 0x32, 0x85, 0xFA, 0xCA, 0x08, 0xA4 }, ++ { 0x59, 0x16, 0x83, 0x3E, 0xBB, 0x05, 0xCD, 0x91, 0x9C, 0xA7, 0xFE, 0x83, 0xB6, 0x92, 0xD3, 0x20, 0x5B, 0xEF, 0x72, 0x39, 0x2B, 0x2C, 0xF6, 0xBB, 0x0A, 0x6D, 0x43, 0xF9, 0x94, 0xF9, 0x5F, 0x11 }, ++ { 0xF6, 0x3A, 0xAB, 0x3E, 0xC6, 0x41, 0xB3, 0xB0, 0x24, 0x96, 0x4C, 0x2B, 0x43, 0x7C, 0x04, 0xF6, 0x04, 0x3C, 0x4C, 0x7E, 0x02, 0x79, 0x23, 0x99, 0x95, 0x40, 0x19, 0x58, 0xF8, 0x6B, 0xBE, 0x54 }, ++ { 0xF1, 0x72, 0xB1, 0x80, 0xBF, 0xB0, 0x97, 0x40, 0x49, 0x31, 0x20, 0xB6, 0x32, 0x6C, 0xBD, 0xC5, 0x61, 0xE4, 0x77, 0xDE, 0xF9, 0xBB, 0xCF, 0xD2, 0x8C, 0xC8, 0xC1, 0xC5, 0xE3, 0x37, 0x9A, 0x31 }, ++ { 0xCB, 0x9B, 0x89, 0xCC, 0x18, 0x38, 0x1D, 0xD9, 0x14, 0x1A, 0xDE, 0x58, 0x86, 0x54, 0xD4, 0xE6, 0xA2, 0x31, 0xD5, 0xBF, 0x49, 0xD4, 0xD5, 0x9A, 0xC2, 0x7D, 0x86, 0x9C, 0xBE, 0x10, 0x0C, 0xF3 }, ++ { 0x7B, 0xD8, 0x81, 0x50, 0x46, 0xFD, 0xD8, 0x10, 0xA9, 0x23, 0xE1, 0x98, 0x4A, 0xAE, 0xBD, 0xCD, 0xF8, 0x4D, 0x87, 0xC8, 0x99, 0x2D, 0x68, 0xB5, 0xEE, 0xB4, 0x60, 0xF9, 0x3E, 0xB3, 0xC8, 0xD7 }, ++ { 0x60, 0x7B, 0xE6, 0x68, 0x62, 0xFD, 0x08, 0xEE, 0x5B, 0x19, 0xFA, 0xCA, 0xC0, 0x9D, 0xFD, 0xBC, 0xD4, 0x0C, 0x31, 0x21, 0x01, 0xD6, 0x6E, 0x6E, 0xBD, 0x2B, 0x84, 0x1F, 0x1B, 0x9A, 0x93, 0x25 }, ++ { 0x9F, 0xE0, 0x3B, 0xBE, 0x69, 0xAB, 0x18, 0x34, 0xF5, 0x21, 0x9B, 0x0D, 0xA8, 0x8A, 0x08, 0xB3, 0x0A, 0x66, 0xC5, 0x91, 0x3F, 0x01, 0x51, 0x96, 0x3C, 0x36, 0x05, 0x60, 0xDB, 0x03, 0x87, 0xB3 }, ++ { 0x90, 0xA8, 0x35, 0x85, 0x71, 0x7B, 0x75, 0xF0, 0xE9, 0xB7, 0x25, 0xE0, 0x55, 0xEE, 0xEE, 0xB9, 0xE7, 0xA0, 0x28, 0xEA, 0x7E, 0x6C, 0xBC, 0x07, 0xB2, 0x09, 0x17, 0xEC, 0x03, 0x63, 0xE3, 0x8C }, ++ { 0x33, 0x6E, 0xA0, 0x53, 0x0F, 0x4A, 0x74, 0x69, 0x12, 0x6E, 0x02, 0x18, 0x58, 0x7E, 0xBB, 0xDE, 0x33, 0x58, 0xA0, 0xB3, 0x1C, 0x29, 0xD2, 0x00, 0xF7, 0xDC, 0x7E, 0xB1, 0x5C, 0x6A, 0xAD, 0xD8 }, ++ { 0xA7, 0x9E, 0x76, 0xDC, 0x0A, 0xBC, 0xA4, 0x39, 0x6F, 0x07, 0x47, 0xCD, 0x7B, 0x74, 0x8D, 0xF9, 0x13, 0x00, 0x76, 0x26, 0xB1, 0xD6, 0x59, 0xDA, 0x0C, 0x1F, 0x78, 0xB9, 0x30, 0x3D, 0x01, 0xA3 }, ++ { 0x44, 0xE7, 0x8A, 0x77, 0x37, 0x56, 0xE0, 0x95, 0x15, 0x19, 0x50, 0x4D, 0x70, 0x38, 0xD2, 0x8D, 0x02, 0x13, 0xA3, 0x7E, 0x0C, 0xE3, 0x75, 0x37, 0x17, 0x57, 0xBC, 0x99, 0x63, 0x11, 0xE3, 0xB8 }, ++ { 0x77, 0xAC, 0x01, 0x2A, 0x3F, 0x75, 0x4D, 0xCF, 0xEA, 0xB5, 0xEB, 0x99, 0x6B, 0xE9, 0xCD, 0x2D, 0x1F, 0x96, 0x11, 0x1B, 0x6E, 0x49, 0xF3, 0x99, 0x4D, 0xF1, 0x81, 0xF2, 0x85, 0x69, 0xD8, 0x25 }, ++ { 0xCE, 0x5A, 0x10, 0xDB, 0x6F, 0xCC, 0xDA, 0xF1, 0x40, 0xAA, 0xA4, 0xDE, 0xD6, 0x25, 0x0A, 0x9C, 0x06, 0xE9, 0x22, 0x2B, 0xC9, 0xF9, 0xF3, 0x65, 0x8A, 0x4A, 0xFF, 0x93, 0x5F, 0x2B, 0x9F, 0x3A }, ++ { 0xEC, 0xC2, 0x03, 0xA7, 0xFE, 0x2B, 0xE4, 0xAB, 0xD5, 0x5B, 0xB5, 0x3E, 0x6E, 0x67, 0x35, 0x72, 0xE0, 0x07, 0x8D, 0xA8, 0xCD, 0x37, 0x5E, 0xF4, 0x30, 0xCC, 0x97, 0xF9, 0xF8, 0x00, 0x83, 0xAF }, ++ { 0x14, 0xA5, 0x18, 0x6D, 0xE9, 0xD7, 0xA1, 0x8B, 0x04, 0x12, 0xB8, 0x56, 0x3E, 0x51, 0xCC, 0x54, 0x33, 0x84, 0x0B, 0x4A, 0x12, 0x9A, 0x8F, 0xF9, 0x63, 0xB3, 0x3A, 0x3C, 0x4A, 0xFE, 0x8E, 0xBB }, ++ { 0x13, 0xF8, 0xEF, 0x95, 0xCB, 0x86, 0xE6, 0xA6, 0x38, 0x93, 0x1C, 0x8E, 0x10, 0x76, 0x73, 0xEB, 0x76, 0xBA, 0x10, 0xD7, 0xC2, 0xCD, 0x70, 0xB9, 0xD9, 0x92, 0x0B, 0xBE, 0xED, 0x92, 0x94, 0x09 }, ++ { 0x0B, 0x33, 0x8F, 0x4E, 0xE1, 0x2F, 0x2D, 0xFC, 0xB7, 0x87, 0x13, 0x37, 0x79, 0x41, 0xE0, 0xB0, 0x63, 0x21, 0x52, 0x58, 0x1D, 0x13, 0x32, 0x51, 0x6E, 0x4A, 0x2C, 0xAB, 0x19, 0x42, 0xCC, 0xA4 }, ++ { 0xEA, 0xAB, 0x0E, 0xC3, 0x7B, 0x3B, 0x8A, 0xB7, 0x96, 0xE9, 0xF5, 0x72, 0x38, 0xDE, 0x14, 0xA2, 0x64, 0xA0, 0x76, 0xF3, 0x88, 0x7D, 0x86, 0xE2, 0x9B, 0xB5, 0x90, 0x6D, 0xB5, 0xA0, 0x0E, 0x02 }, ++ { 0x23, 0xCB, 0x68, 0xB8, 0xC0, 0xE6, 0xDC, 0x26, 0xDC, 0x27, 0x76, 0x6D, 0xDC, 0x0A, 0x13, 0xA9, 0x94, 0x38, 0xFD, 0x55, 0x61, 0x7A, 0xA4, 0x09, 0x5D, 0x8F, 0x96, 0x97, 0x20, 0xC8, 0x72, 0xDF }, ++ { 0x09, 0x1D, 0x8E, 0xE3, 0x0D, 0x6F, 0x29, 0x68, 0xD4, 0x6B, 0x68, 0x7D, 0xD6, 0x52, 0x92, 0x66, 0x57, 0x42, 0xDE, 0x0B, 0xB8, 0x3D, 0xCC, 0x00, 0x04, 0xC7, 0x2C, 0xE1, 0x00, 0x07, 0xA5, 0x49 }, ++ { 0x7F, 0x50, 0x7A, 0xBC, 0x6D, 0x19, 0xBA, 0x00, 0xC0, 0x65, 0xA8, 0x76, 0xEC, 0x56, 0x57, 0x86, 0x88, 0x82, 0xD1, 0x8A, 0x22, 0x1B, 0xC4, 0x6C, 0x7A, 0x69, 0x12, 0x54, 0x1F, 0x5B, 0xC7, 0xBA }, ++ { 0xA0, 0x60, 0x7C, 0x24, 0xE1, 0x4E, 0x8C, 0x22, 0x3D, 0xB0, 0xD7, 0x0B, 0x4D, 0x30, 0xEE, 0x88, 0x01, 0x4D, 0x60, 0x3F, 0x43, 0x7E, 0x9E, 0x02, 0xAA, 0x7D, 0xAF, 0xA3, 0xCD, 0xFB, 0xAD, 0x94 }, ++ { 0xDD, 0xBF, 0xEA, 0x75, 0xCC, 0x46, 0x78, 0x82, 0xEB, 0x34, 0x83, 0xCE, 0x5E, 0x2E, 0x75, 0x6A, 0x4F, 0x47, 0x01, 0xB7, 0x6B, 0x44, 0x55, 0x19, 0xE8, 0x9F, 0x22, 0xD6, 0x0F, 0xA8, 0x6E, 0x06 }, ++ { 0x0C, 0x31, 0x1F, 0x38, 0xC3, 0x5A, 0x4F, 0xB9, 0x0D, 0x65, 0x1C, 0x28, 0x9D, 0x48, 0x68, 0x56, 0xCD, 0x14, 0x13, 0xDF, 0x9B, 0x06, 0x77, 0xF5, 0x3E, 0xCE, 0x2C, 0xD9, 0xE4, 0x77, 0xC6, 0x0A }, ++ { 0x46, 0xA7, 0x3A, 0x8D, 0xD3, 0xE7, 0x0F, 0x59, 0xD3, 0x94, 0x2C, 0x01, 0xDF, 0x59, 0x9D, 0xEF, 0x78, 0x3C, 0x9D, 0xA8, 0x2F, 0xD8, 0x32, 0x22, 0xCD, 0x66, 0x2B, 0x53, 0xDC, 0xE7, 0xDB, 0xDF }, ++ { 0xAD, 0x03, 0x8F, 0xF9, 0xB1, 0x4D, 0xE8, 0x4A, 0x80, 0x1E, 0x4E, 0x62, 0x1C, 0xE5, 0xDF, 0x02, 0x9D, 0xD9, 0x35, 0x20, 0xD0, 0xC2, 0xFA, 0x38, 0xBF, 0xF1, 0x76, 0xA8, 0xB1, 0xD1, 0x69, 0x8C }, ++ { 0xAB, 0x70, 0xC5, 0xDF, 0xBD, 0x1E, 0xA8, 0x17, 0xFE, 0xD0, 0xCD, 0x06, 0x72, 0x93, 0xAB, 0xF3, 0x19, 0xE5, 0xD7, 0x90, 0x1C, 0x21, 0x41, 0xD5, 0xD9, 0x9B, 0x23, 0xF0, 0x3A, 0x38, 0xE7, 0x48 }, ++ { 0x1F, 0xFF, 0xDA, 0x67, 0x93, 0x2B, 0x73, 0xC8, 0xEC, 0xAF, 0x00, 0x9A, 0x34, 0x91, 0xA0, 0x26, 0x95, 0x3B, 0xAB, 0xFE, 0x1F, 0x66, 0x3B, 0x06, 0x97, 0xC3, 0xC4, 0xAE, 0x8B, 0x2E, 0x7D, 0xCB }, ++ { 0xB0, 0xD2, 0xCC, 0x19, 0x47, 0x2D, 0xD5, 0x7F, 0x2B, 0x17, 0xEF, 0xC0, 0x3C, 0x8D, 0x58, 0xC2, 0x28, 0x3D, 0xBB, 0x19, 0xDA, 0x57, 0x2F, 0x77, 0x55, 0x85, 0x5A, 0xA9, 0x79, 0x43, 0x17, 0xA0 }, ++ { 0xA0, 0xD1, 0x9A, 0x6E, 0xE3, 0x39, 0x79, 0xC3, 0x25, 0x51, 0x0E, 0x27, 0x66, 0x22, 0xDF, 0x41, 0xF7, 0x15, 0x83, 0xD0, 0x75, 0x01, 0xB8, 0x70, 0x71, 0x12, 0x9A, 0x0A, 0xD9, 0x47, 0x32, 0xA5 }, ++ { 0x72, 0x46, 0x42, 0xA7, 0x03, 0x2D, 0x10, 0x62, 0xB8, 0x9E, 0x52, 0xBE, 0xA3, 0x4B, 0x75, 0xDF, 0x7D, 0x8F, 0xE7, 0x72, 0xD9, 0xFE, 0x3C, 0x93, 0xDD, 0xF3, 0xC4, 0x54, 0x5A, 0xB5, 0xA9, 0x9B }, ++ { 0xAD, 0xE5, 0xEA, 0xA7, 0xE6, 0x1F, 0x67, 0x2D, 0x58, 0x7E, 0xA0, 0x3D, 0xAE, 0x7D, 0x7B, 0x55, 0x22, 0x9C, 0x01, 0xD0, 0x6B, 0xC0, 0xA5, 0x70, 0x14, 0x36, 0xCB, 0xD1, 0x83, 0x66, 0xA6, 0x26 }, ++ { 0x01, 0x3B, 0x31, 0xEB, 0xD2, 0x28, 0xFC, 0xDD, 0xA5, 0x1F, 0xAB, 0xB0, 0x3B, 0xB0, 0x2D, 0x60, 0xAC, 0x20, 0xCA, 0x21, 0x5A, 0xAF, 0xA8, 0x3B, 0xDD, 0x85, 0x5E, 0x37, 0x55, 0xA3, 0x5F, 0x0B }, ++ { 0x33, 0x2E, 0xD4, 0x0B, 0xB1, 0x0D, 0xDE, 0x3C, 0x95, 0x4A, 0x75, 0xD7, 0xB8, 0x99, 0x9D, 0x4B, 0x26, 0xA1, 0xC0, 0x63, 0xC1, 0xDC, 0x6E, 0x32, 0xC1, 0xD9, 0x1B, 0xAB, 0x7B, 0xBB, 0x7D, 0x16 }, ++ { 0xC7, 0xA1, 0x97, 0xB3, 0xA0, 0x5B, 0x56, 0x6B, 0xCC, 0x9F, 0xAC, 0xD2, 0x0E, 0x44, 0x1D, 0x6F, 0x6C, 0x28, 0x60, 0xAC, 0x96, 0x51, 0xCD, 0x51, 0xD6, 0xB9, 0xD2, 0xCD, 0xEE, 0xEA, 0x03, 0x90 }, ++ { 0xBD, 0x9C, 0xF6, 0x4E, 0xA8, 0x95, 0x3C, 0x03, 0x71, 0x08, 0xE6, 0xF6, 0x54, 0x91, 0x4F, 0x39, 0x58, 0xB6, 0x8E, 0x29, 0xC1, 0x67, 0x00, 0xDC, 0x18, 0x4D, 0x94, 0xA2, 0x17, 0x08, 0xFF, 0x60 }, ++ { 0x88, 0x35, 0xB0, 0xAC, 0x02, 0x11, 0x51, 0xDF, 0x71, 0x64, 0x74, 0xCE, 0x27, 0xCE, 0x4D, 0x3C, 0x15, 0xF0, 0xB2, 0xDA, 0xB4, 0x80, 0x03, 0xCF, 0x3F, 0x3E, 0xFD, 0x09, 0x45, 0x10, 0x6B, 0x9A }, ++ { 0x3B, 0xFE, 0xFA, 0x33, 0x01, 0xAA, 0x55, 0xC0, 0x80, 0x19, 0x0C, 0xFF, 0xDA, 0x8E, 0xAE, 0x51, 0xD9, 0xAF, 0x48, 0x8B, 0x4C, 0x1F, 0x24, 0xC3, 0xD9, 0xA7, 0x52, 0x42, 0xFD, 0x8E, 0xA0, 0x1D }, ++ { 0x08, 0x28, 0x4D, 0x14, 0x99, 0x3C, 0xD4, 0x7D, 0x53, 0xEB, 0xAE, 0xCF, 0x0D, 0xF0, 0x47, 0x8C, 0xC1, 0x82, 0xC8, 0x9C, 0x00, 0xE1, 0x85, 0x9C, 0x84, 0x85, 0x16, 0x86, 0xDD, 0xF2, 0xC1, 0xB7 }, ++ { 0x1E, 0xD7, 0xEF, 0x9F, 0x04, 0xC2, 0xAC, 0x8D, 0xB6, 0xA8, 0x64, 0xDB, 0x13, 0x10, 0x87, 0xF2, 0x70, 0x65, 0x09, 0x8E, 0x69, 0xC3, 0xFE, 0x78, 0x71, 0x8D, 0x9B, 0x94, 0x7F, 0x4A, 0x39, 0xD0 }, ++ { 0xC1, 0x61, 0xF2, 0xDC, 0xD5, 0x7E, 0x9C, 0x14, 0x39, 0xB3, 0x1A, 0x9D, 0xD4, 0x3D, 0x8F, 0x3D, 0x7D, 0xD8, 0xF0, 0xEB, 0x7C, 0xFA, 0xC6, 0xFB, 0x25, 0xA0, 0xF2, 0x8E, 0x30, 0x6F, 0x06, 0x61 }, ++ { 0xC0, 0x19, 0x69, 0xAD, 0x34, 0xC5, 0x2C, 0xAF, 0x3D, 0xC4, 0xD8, 0x0D, 0x19, 0x73, 0x5C, 0x29, 0x73, 0x1A, 0xC6, 0xE7, 0xA9, 0x20, 0x85, 0xAB, 0x92, 0x50, 0xC4, 0x8D, 0xEA, 0x48, 0xA3, 0xFC }, ++ { 0x17, 0x20, 0xB3, 0x65, 0x56, 0x19, 0xD2, 0xA5, 0x2B, 0x35, 0x21, 0xAE, 0x0E, 0x49, 0xE3, 0x45, 0xCB, 0x33, 0x89, 0xEB, 0xD6, 0x20, 0x8A, 0xCA, 0xF9, 0xF1, 0x3F, 0xDA, 0xCC, 0xA8, 0xBE, 0x49 }, ++ { 0x75, 0x62, 0x88, 0x36, 0x1C, 0x83, 0xE2, 0x4C, 0x61, 0x7C, 0xF9, 0x5C, 0x90, 0x5B, 0x22, 0xD0, 0x17, 0xCD, 0xC8, 0x6F, 0x0B, 0xF1, 0xD6, 0x58, 0xF4, 0x75, 0x6C, 0x73, 0x79, 0x87, 0x3B, 0x7F }, ++ { 0xE7, 0xD0, 0xED, 0xA3, 0x45, 0x26, 0x93, 0xB7, 0x52, 0xAB, 0xCD, 0xA1, 0xB5, 0x5E, 0x27, 0x6F, 0x82, 0x69, 0x8F, 0x5F, 0x16, 0x05, 0x40, 0x3E, 0xFF, 0x83, 0x0B, 0xEA, 0x00, 0x71, 0xA3, 0x94 }, ++ { 0x2C, 0x82, 0xEC, 0xAA, 0x6B, 0x84, 0x80, 0x3E, 0x04, 0x4A, 0xF6, 0x31, 0x18, 0xAF, 0xE5, 0x44, 0x68, 0x7C, 0xB6, 0xE6, 0xC7, 0xDF, 0x49, 0xED, 0x76, 0x2D, 0xFD, 0x7C, 0x86, 0x93, 0xA1, 0xBC }, ++ { 0x61, 0x36, 0xCB, 0xF4, 0xB4, 0x41, 0x05, 0x6F, 0xA1, 0xE2, 0x72, 0x24, 0x98, 0x12, 0x5D, 0x6D, 0xED, 0x45, 0xE1, 0x7B, 0x52, 0x14, 0x39, 0x59, 0xC7, 0xF4, 0xD4, 0xE3, 0x95, 0x21, 0x8A, 0xC2 }, ++ { 0x72, 0x1D, 0x32, 0x45, 0xAA, 0xFE, 0xF2, 0x7F, 0x6A, 0x62, 0x4F, 0x47, 0x95, 0x4B, 0x6C, 0x25, 0x50, 0x79, 0x52, 0x6F, 0xFA, 0x25, 0xE9, 0xFF, 0x77, 0xE5, 0xDC, 0xFF, 0x47, 0x3B, 0x15, 0x97 }, ++ { 0x9D, 0xD2, 0xFB, 0xD8, 0xCE, 0xF1, 0x6C, 0x35, 0x3C, 0x0A, 0xC2, 0x11, 0x91, 0xD5, 0x09, 0xEB, 0x28, 0xDD, 0x9E, 0x3E, 0x0D, 0x8C, 0xEA, 0x5D, 0x26, 0xCA, 0x83, 0x93, 0x93, 0x85, 0x1C, 0x3A }, ++ { 0xB2, 0x39, 0x4C, 0xEA, 0xCD, 0xEB, 0xF2, 0x1B, 0xF9, 0xDF, 0x2C, 0xED, 0x98, 0xE5, 0x8F, 0x1C, 0x3A, 0x4B, 0xBB, 0xFF, 0x66, 0x0D, 0xD9, 0x00, 0xF6, 0x22, 0x02, 0xD6, 0x78, 0x5C, 0xC4, 0x6E }, ++ { 0x57, 0x08, 0x9F, 0x22, 0x27, 0x49, 0xAD, 0x78, 0x71, 0x76, 0x5F, 0x06, 0x2B, 0x11, 0x4F, 0x43, 0xBA, 0x20, 0xEC, 0x56, 0x42, 0x2A, 0x8B, 0x1E, 0x3F, 0x87, 0x19, 0x2C, 0x0E, 0xA7, 0x18, 0xC6 }, ++ { 0xE4, 0x9A, 0x94, 0x59, 0x96, 0x1C, 0xD3, 0x3C, 0xDF, 0x4A, 0xAE, 0x1B, 0x10, 0x78, 0xA5, 0xDE, 0xA7, 0xC0, 0x40, 0xE0, 0xFE, 0xA3, 0x40, 0xC9, 0x3A, 0x72, 0x48, 0x72, 0xFC, 0x4A, 0xF8, 0x06 }, ++ { 0xED, 0xE6, 0x7F, 0x72, 0x0E, 0xFF, 0xD2, 0xCA, 0x9C, 0x88, 0x99, 0x41, 0x52, 0xD0, 0x20, 0x1D, 0xEE, 0x6B, 0x0A, 0x2D, 0x2C, 0x07, 0x7A, 0xCA, 0x6D, 0xAE, 0x29, 0xF7, 0x3F, 0x8B, 0x63, 0x09 }, ++ { 0xE0, 0xF4, 0x34, 0xBF, 0x22, 0xE3, 0x08, 0x80, 0x39, 0xC2, 0x1F, 0x71, 0x9F, 0xFC, 0x67, 0xF0, 0xF2, 0xCB, 0x5E, 0x98, 0xA7, 0xA0, 0x19, 0x4C, 0x76, 0xE9, 0x6B, 0xF4, 0xE8, 0xE1, 0x7E, 0x61 }, ++ { 0x27, 0x7C, 0x04, 0xE2, 0x85, 0x34, 0x84, 0xA4, 0xEB, 0xA9, 0x10, 0xAD, 0x33, 0x6D, 0x01, 0xB4, 0x77, 0xB6, 0x7C, 0xC2, 0x00, 0xC5, 0x9F, 0x3C, 0x8D, 0x77, 0xEE, 0xF8, 0x49, 0x4F, 0x29, 0xCD }, ++ { 0x15, 0x6D, 0x57, 0x47, 0xD0, 0xC9, 0x9C, 0x7F, 0x27, 0x09, 0x7D, 0x7B, 0x7E, 0x00, 0x2B, 0x2E, 0x18, 0x5C, 0xB7, 0x2D, 0x8D, 0xD7, 0xEB, 0x42, 0x4A, 0x03, 0x21, 0x52, 0x81, 0x61, 0x21, 0x9F }, ++ { 0x20, 0xDD, 0xD1, 0xED, 0x9B, 0x1C, 0xA8, 0x03, 0x94, 0x6D, 0x64, 0xA8, 0x3A, 0xE4, 0x65, 0x9D, 0xA6, 0x7F, 0xBA, 0x7A, 0x1A, 0x3E, 0xDD, 0xB1, 0xE1, 0x03, 0xC0, 0xF5, 0xE0, 0x3E, 0x3A, 0x2C }, ++ { 0xF0, 0xAF, 0x60, 0x4D, 0x3D, 0xAB, 0xBF, 0x9A, 0x0F, 0x2A, 0x7D, 0x3D, 0xDA, 0x6B, 0xD3, 0x8B, 0xBA, 0x72, 0xC6, 0xD0, 0x9B, 0xE4, 0x94, 0xFC, 0xEF, 0x71, 0x3F, 0xF1, 0x01, 0x89, 0xB6, 0xE6 }, ++ { 0x98, 0x02, 0xBB, 0x87, 0xDE, 0xF4, 0xCC, 0x10, 0xC4, 0xA5, 0xFD, 0x49, 0xAA, 0x58, 0xDF, 0xE2, 0xF3, 0xFD, 0xDB, 0x46, 0xB4, 0x70, 0x88, 0x14, 0xEA, 0xD8, 0x1D, 0x23, 0xBA, 0x95, 0x13, 0x9B }, ++ { 0x4F, 0x8C, 0xE1, 0xE5, 0x1D, 0x2F, 0xE7, 0xF2, 0x40, 0x43, 0xA9, 0x04, 0xD8, 0x98, 0xEB, 0xFC, 0x91, 0x97, 0x54, 0x18, 0x75, 0x34, 0x13, 0xAA, 0x09, 0x9B, 0x79, 0x5E, 0xCB, 0x35, 0xCE, 0xDB }, ++ { 0xBD, 0xDC, 0x65, 0x14, 0xD7, 0xEE, 0x6A, 0xCE, 0x0A, 0x4A, 0xC1, 0xD0, 0xE0, 0x68, 0x11, 0x22, 0x88, 0xCB, 0xCF, 0x56, 0x04, 0x54, 0x64, 0x27, 0x05, 0x63, 0x01, 0x77, 0xCB, 0xA6, 0x08, 0xBD }, ++ { 0xD6, 0x35, 0x99, 0x4F, 0x62, 0x91, 0x51, 0x7B, 0x02, 0x81, 0xFF, 0xDD, 0x49, 0x6A, 0xFA, 0x86, 0x27, 0x12, 0xE5, 0xB3, 0xC4, 0xE5, 0x2E, 0x4C, 0xD5, 0xFD, 0xAE, 0x8C, 0x0E, 0x72, 0xFB, 0x08 }, ++ { 0x87, 0x8D, 0x9C, 0xA6, 0x00, 0xCF, 0x87, 0xE7, 0x69, 0xCC, 0x30, 0x5C, 0x1B, 0x35, 0x25, 0x51, 0x86, 0x61, 0x5A, 0x73, 0xA0, 0xDA, 0x61, 0x3B, 0x5F, 0x1C, 0x98, 0xDB, 0xF8, 0x12, 0x83, 0xEA }, ++ { 0xA6, 0x4E, 0xBE, 0x5D, 0xC1, 0x85, 0xDE, 0x9F, 0xDD, 0xE7, 0x60, 0x7B, 0x69, 0x98, 0x70, 0x2E, 0xB2, 0x34, 0x56, 0x18, 0x49, 0x57, 0x30, 0x7D, 0x2F, 0xA7, 0x2E, 0x87, 0xA4, 0x77, 0x02, 0xD6 }, ++ { 0xCE, 0x50, 0xEA, 0xB7, 0xB5, 0xEB, 0x52, 0xBD, 0xC9, 0xAD, 0x8E, 0x5A, 0x48, 0x0A, 0xB7, 0x80, 0xCA, 0x93, 0x20, 0xE4, 0x43, 0x60, 0xB1, 0xFE, 0x37, 0xE0, 0x3F, 0x2F, 0x7A, 0xD7, 0xDE, 0x01 }, ++ { 0xEE, 0xDD, 0xB7, 0xC0, 0xDB, 0x6E, 0x30, 0xAB, 0xE6, 0x6D, 0x79, 0xE3, 0x27, 0x51, 0x1E, 0x61, 0xFC, 0xEB, 0xBC, 0x29, 0xF1, 0x59, 0xB4, 0x0A, 0x86, 0xB0, 0x46, 0xEC, 0xF0, 0x51, 0x38, 0x23 }, ++ { 0x78, 0x7F, 0xC9, 0x34, 0x40, 0xC1, 0xEC, 0x96, 0xB5, 0xAD, 0x01, 0xC1, 0x6C, 0xF7, 0x79, 0x16, 0xA1, 0x40, 0x5F, 0x94, 0x26, 0x35, 0x6E, 0xC9, 0x21, 0xD8, 0xDF, 0xF3, 0xEA, 0x63, 0xB7, 0xE0 }, ++ { 0x7F, 0x0D, 0x5E, 0xAB, 0x47, 0xEE, 0xFD, 0xA6, 0x96, 0xC0, 0xBF, 0x0F, 0xBF, 0x86, 0xAB, 0x21, 0x6F, 0xCE, 0x46, 0x1E, 0x93, 0x03, 0xAB, 0xA6, 0xAC, 0x37, 0x41, 0x20, 0xE8, 0x90, 0xE8, 0xDF }, ++ { 0xB6, 0x80, 0x04, 0xB4, 0x2F, 0x14, 0xAD, 0x02, 0x9F, 0x4C, 0x2E, 0x03, 0xB1, 0xD5, 0xEB, 0x76, 0xD5, 0x71, 0x60, 0xE2, 0x64, 0x76, 0xD2, 0x11, 0x31, 0xBE, 0xF2, 0x0A, 0xDA, 0x7D, 0x27, 0xF4 }, ++ { 0xB0, 0xC4, 0xEB, 0x18, 0xAE, 0x25, 0x0B, 0x51, 0xA4, 0x13, 0x82, 0xEA, 0xD9, 0x2D, 0x0D, 0xC7, 0x45, 0x5F, 0x93, 0x79, 0xFC, 0x98, 0x84, 0x42, 0x8E, 0x47, 0x70, 0x60, 0x8D, 0xB0, 0xFA, 0xEC }, ++ { 0xF9, 0x2B, 0x7A, 0x87, 0x0C, 0x05, 0x9F, 0x4D, 0x46, 0x46, 0x4C, 0x82, 0x4E, 0xC9, 0x63, 0x55, 0x14, 0x0B, 0xDC, 0xE6, 0x81, 0x32, 0x2C, 0xC3, 0xA9, 0x92, 0xFF, 0x10, 0x3E, 0x3F, 0xEA, 0x52 }, ++ { 0x53, 0x64, 0x31, 0x26, 0x14, 0x81, 0x33, 0x98, 0xCC, 0x52, 0x5D, 0x4C, 0x4E, 0x14, 0x6E, 0xDE, 0xB3, 0x71, 0x26, 0x5F, 0xBA, 0x19, 0x13, 0x3A, 0x2C, 0x3D, 0x21, 0x59, 0x29, 0x8A, 0x17, 0x42 }, ++ { 0xF6, 0x62, 0x0E, 0x68, 0xD3, 0x7F, 0xB2, 0xAF, 0x50, 0x00, 0xFC, 0x28, 0xE2, 0x3B, 0x83, 0x22, 0x97, 0xEC, 0xD8, 0xBC, 0xE9, 0x9E, 0x8B, 0xE4, 0xD0, 0x4E, 0x85, 0x30, 0x9E, 0x3D, 0x33, 0x74 }, ++ { 0x53, 0x16, 0xA2, 0x79, 0x69, 0xD7, 0xFE, 0x04, 0xFF, 0x27, 0xB2, 0x83, 0x96, 0x1B, 0xFF, 0xC3, 0xBF, 0x5D, 0xFB, 0x32, 0xFB, 0x6A, 0x89, 0xD1, 0x01, 0xC6, 0xC3, 0xB1, 0x93, 0x7C, 0x28, 0x71 }, ++ { 0x81, 0xD1, 0x66, 0x4F, 0xDF, 0x3C, 0xB3, 0x3C, 0x24, 0xEE, 0xBA, 0xC0, 0xBD, 0x64, 0x24, 0x4B, 0x77, 0xC4, 0xAB, 0xEA, 0x90, 0xBB, 0xE8, 0xB5, 0xEE, 0x0B, 0x2A, 0xAF, 0xCF, 0x2D, 0x6A, 0x53 }, ++ { 0x34, 0x57, 0x82, 0xF2, 0x95, 0xB0, 0x88, 0x03, 0x52, 0xE9, 0x24, 0xA0, 0x46, 0x7B, 0x5F, 0xBC, 0x3E, 0x8F, 0x3B, 0xFB, 0xC3, 0xC7, 0xE4, 0x8B, 0x67, 0x09, 0x1F, 0xB5, 0xE8, 0x0A, 0x94, 0x42 }, ++ { 0x79, 0x41, 0x11, 0xEA, 0x6C, 0xD6, 0x5E, 0x31, 0x1F, 0x74, 0xEE, 0x41, 0xD4, 0x76, 0xCB, 0x63, 0x2C, 0xE1, 0xE4, 0xB0, 0x51, 0xDC, 0x1D, 0x9E, 0x9D, 0x06, 0x1A, 0x19, 0xE1, 0xD0, 0xBB, 0x49 }, ++ { 0x2A, 0x85, 0xDA, 0xF6, 0x13, 0x88, 0x16, 0xB9, 0x9B, 0xF8, 0xD0, 0x8B, 0xA2, 0x11, 0x4B, 0x7A, 0xB0, 0x79, 0x75, 0xA7, 0x84, 0x20, 0xC1, 0xA3, 0xB0, 0x6A, 0x77, 0x7C, 0x22, 0xDD, 0x8B, 0xCB }, ++ { 0x89, 0xB0, 0xD5, 0xF2, 0x89, 0xEC, 0x16, 0x40, 0x1A, 0x06, 0x9A, 0x96, 0x0D, 0x0B, 0x09, 0x3E, 0x62, 0x5D, 0xA3, 0xCF, 0x41, 0xEE, 0x29, 0xB5, 0x9B, 0x93, 0x0C, 0x58, 0x20, 0x14, 0x54, 0x55 }, ++ { 0xD0, 0xFD, 0xCB, 0x54, 0x39, 0x43, 0xFC, 0x27, 0xD2, 0x08, 0x64, 0xF5, 0x21, 0x81, 0x47, 0x1B, 0x94, 0x2C, 0xC7, 0x7C, 0xA6, 0x75, 0xBC, 0xB3, 0x0D, 0xF3, 0x1D, 0x35, 0x8E, 0xF7, 0xB1, 0xEB }, ++ { 0xB1, 0x7E, 0xA8, 0xD7, 0x70, 0x63, 0xC7, 0x09, 0xD4, 0xDC, 0x6B, 0x87, 0x94, 0x13, 0xC3, 0x43, 0xE3, 0x79, 0x0E, 0x9E, 0x62, 0xCA, 0x85, 0xB7, 0x90, 0x0B, 0x08, 0x6F, 0x6B, 0x75, 0xC6, 0x72 }, ++ { 0xE7, 0x1A, 0x3E, 0x2C, 0x27, 0x4D, 0xB8, 0x42, 0xD9, 0x21, 0x14, 0xF2, 0x17, 0xE2, 0xC0, 0xEA, 0xC8, 0xB4, 0x50, 0x93, 0xFD, 0xFD, 0x9D, 0xF4, 0xCA, 0x71, 0x62, 0x39, 0x48, 0x62, 0xD5, 0x01 }, ++ { 0xC0, 0x47, 0x67, 0x59, 0xAB, 0x7A, 0xA3, 0x33, 0x23, 0x4F, 0x6B, 0x44, 0xF5, 0xFD, 0x85, 0x83, 0x90, 0xEC, 0x23, 0x69, 0x4C, 0x62, 0x2C, 0xB9, 0x86, 0xE7, 0x69, 0xC7, 0x8E, 0xDD, 0x73, 0x3E }, ++ { 0x9A, 0xB8, 0xEA, 0xBB, 0x14, 0x16, 0x43, 0x4D, 0x85, 0x39, 0x13, 0x41, 0xD5, 0x69, 0x93, 0xC5, 0x54, 0x58, 0x16, 0x7D, 0x44, 0x18, 0xB1, 0x9A, 0x0F, 0x2A, 0xD8, 0xB7, 0x9A, 0x83, 0xA7, 0x5B }, ++ { 0x79, 0x92, 0xD0, 0xBB, 0xB1, 0x5E, 0x23, 0x82, 0x6F, 0x44, 0x3E, 0x00, 0x50, 0x5D, 0x68, 0xD3, 0xED, 0x73, 0x72, 0x99, 0x5A, 0x5C, 0x3E, 0x49, 0x86, 0x54, 0x10, 0x2F, 0xBC, 0xD0, 0x96, 0x4E }, ++ { 0xC0, 0x21, 0xB3, 0x00, 0x85, 0x15, 0x14, 0x35, 0xDF, 0x33, 0xB0, 0x07, 0xCC, 0xEC, 0xC6, 0x9D, 0xF1, 0x26, 0x9F, 0x39, 0xBA, 0x25, 0x09, 0x2B, 0xED, 0x59, 0xD9, 0x32, 0xAC, 0x0F, 0xDC, 0x28 }, ++ { 0x91, 0xA2, 0x5E, 0xC0, 0xEC, 0x0D, 0x9A, 0x56, 0x7F, 0x89, 0xC4, 0xBF, 0xE1, 0xA6, 0x5A, 0x0E, 0x43, 0x2D, 0x07, 0x06, 0x4B, 0x41, 0x90, 0xE2, 0x7D, 0xFB, 0x81, 0x90, 0x1F, 0xD3, 0x13, 0x9B }, ++ { 0x59, 0x50, 0xD3, 0x9A, 0x23, 0xE1, 0x54, 0x5F, 0x30, 0x12, 0x70, 0xAA, 0x1A, 0x12, 0xF2, 0xE6, 0xC4, 0x53, 0x77, 0x6E, 0x4D, 0x63, 0x55, 0xDE, 0x42, 0x5C, 0xC1, 0x53, 0xF9, 0x81, 0x88, 0x67 }, ++ { 0xD7, 0x9F, 0x14, 0x72, 0x0C, 0x61, 0x0A, 0xF1, 0x79, 0xA3, 0x76, 0x5D, 0x4B, 0x7C, 0x09, 0x68, 0xF9, 0x77, 0x96, 0x2D, 0xBF, 0x65, 0x5B, 0x52, 0x12, 0x72, 0xB6, 0xF1, 0xE1, 0x94, 0x48, 0x8E }, ++ { 0xE9, 0x53, 0x1B, 0xFC, 0x8B, 0x02, 0x99, 0x5A, 0xEA, 0xA7, 0x5B, 0xA2, 0x70, 0x31, 0xFA, 0xDB, 0xCB, 0xF4, 0xA0, 0xDA, 0xB8, 0x96, 0x1D, 0x92, 0x96, 0xCD, 0x7E, 0x84, 0xD2, 0x5D, 0x60, 0x06 }, ++ { 0x34, 0xE9, 0xC2, 0x6A, 0x01, 0xD7, 0xF1, 0x61, 0x81, 0xB4, 0x54, 0xA9, 0xD1, 0x62, 0x3C, 0x23, 0x3C, 0xB9, 0x9D, 0x31, 0xC6, 0x94, 0x65, 0x6E, 0x94, 0x13, 0xAC, 0xA3, 0xE9, 0x18, 0x69, 0x2F }, ++ { 0xD9, 0xD7, 0x42, 0x2F, 0x43, 0x7B, 0xD4, 0x39, 0xDD, 0xD4, 0xD8, 0x83, 0xDA, 0xE2, 0xA0, 0x83, 0x50, 0x17, 0x34, 0x14, 0xBE, 0x78, 0x15, 0x51, 0x33, 0xFF, 0xF1, 0x96, 0x4C, 0x3D, 0x79, 0x72 }, ++ { 0x4A, 0xEE, 0x0C, 0x7A, 0xAF, 0x07, 0x54, 0x14, 0xFF, 0x17, 0x93, 0xEA, 0xD7, 0xEA, 0xCA, 0x60, 0x17, 0x75, 0xC6, 0x15, 0xDB, 0xD6, 0x0B, 0x64, 0x0B, 0x0A, 0x9F, 0x0C, 0xE5, 0x05, 0xD4, 0x35 }, ++ { 0x6B, 0xFD, 0xD1, 0x54, 0x59, 0xC8, 0x3B, 0x99, 0xF0, 0x96, 0xBF, 0xB4, 0x9E, 0xE8, 0x7B, 0x06, 0x3D, 0x69, 0xC1, 0x97, 0x4C, 0x69, 0x28, 0xAC, 0xFC, 0xFB, 0x40, 0x99, 0xF8, 0xC4, 0xEF, 0x67 }, ++ { 0x9F, 0xD1, 0xC4, 0x08, 0xFD, 0x75, 0xC3, 0x36, 0x19, 0x3A, 0x2A, 0x14, 0xD9, 0x4F, 0x6A, 0xF5, 0xAD, 0xF0, 0x50, 0xB8, 0x03, 0x87, 0xB4, 0xB0, 0x10, 0xFB, 0x29, 0xF4, 0xCC, 0x72, 0x70, 0x7C }, ++ { 0x13, 0xC8, 0x84, 0x80, 0xA5, 0xD0, 0x0D, 0x6C, 0x8C, 0x7A, 0xD2, 0x11, 0x0D, 0x76, 0xA8, 0x2D, 0x9B, 0x70, 0xF4, 0xFA, 0x66, 0x96, 0xD4, 0xE5, 0xDD, 0x42, 0xA0, 0x66, 0xDC, 0xAF, 0x99, 0x20 }, ++ { 0x82, 0x0E, 0x72, 0x5E, 0xE2, 0x5F, 0xE8, 0xFD, 0x3A, 0x8D, 0x5A, 0xBE, 0x4C, 0x46, 0xC3, 0xBA, 0x88, 0x9D, 0xE6, 0xFA, 0x91, 0x91, 0xAA, 0x22, 0xBA, 0x67, 0xD5, 0x70, 0x54, 0x21, 0x54, 0x2B }, ++ { 0x32, 0xD9, 0x3A, 0x0E, 0xB0, 0x2F, 0x42, 0xFB, 0xBC, 0xAF, 0x2B, 0xAD, 0x00, 0x85, 0xB2, 0x82, 0xE4, 0x60, 0x46, 0xA4, 0xDF, 0x7A, 0xD1, 0x06, 0x57, 0xC9, 0xD6, 0x47, 0x63, 0x75, 0xB9, 0x3E }, ++ { 0xAD, 0xC5, 0x18, 0x79, 0x05, 0xB1, 0x66, 0x9C, 0xD8, 0xEC, 0x9C, 0x72, 0x1E, 0x19, 0x53, 0x78, 0x6B, 0x9D, 0x89, 0xA9, 0xBA, 0xE3, 0x07, 0x80, 0xF1, 0xE1, 0xEA, 0xB2, 0x4A, 0x00, 0x52, 0x3C }, ++ { 0xE9, 0x07, 0x56, 0xFF, 0x7F, 0x9A, 0xD8, 0x10, 0xB2, 0x39, 0xA1, 0x0C, 0xED, 0x2C, 0xF9, 0xB2, 0x28, 0x43, 0x54, 0xC1, 0xF8, 0xC7, 0xE0, 0xAC, 0xCC, 0x24, 0x61, 0xDC, 0x79, 0x6D, 0x6E, 0x89 }, ++ { 0x12, 0x51, 0xF7, 0x6E, 0x56, 0x97, 0x84, 0x81, 0x87, 0x53, 0x59, 0x80, 0x1D, 0xB5, 0x89, 0xA0, 0xB2, 0x2F, 0x86, 0xD8, 0xD6, 0x34, 0xDC, 0x04, 0x50, 0x6F, 0x32, 0x2E, 0xD7, 0x8F, 0x17, 0xE8 }, ++ { 0x3A, 0xFA, 0x89, 0x9F, 0xD9, 0x80, 0xE7, 0x3E, 0xCB, 0x7F, 0x4D, 0x8B, 0x8F, 0x29, 0x1D, 0xC9, 0xAF, 0x79, 0x6B, 0xC6, 0x5D, 0x27, 0xF9, 0x74, 0xC6, 0xF1, 0x93, 0xC9, 0x19, 0x1A, 0x09, 0xFD }, ++ { 0xAA, 0x30, 0x5B, 0xE2, 0x6E, 0x5D, 0xED, 0xDC, 0x3C, 0x10, 0x10, 0xCB, 0xC2, 0x13, 0xF9, 0x5F, 0x05, 0x1C, 0x78, 0x5C, 0x5B, 0x43, 0x1E, 0x6A, 0x7C, 0xD0, 0x48, 0xF1, 0x61, 0x78, 0x75, 0x28 }, ++ { 0x8E, 0xA1, 0x88, 0x4F, 0xF3, 0x2E, 0x9D, 0x10, 0xF0, 0x39, 0xB4, 0x07, 0xD0, 0xD4, 0x4E, 0x7E, 0x67, 0x0A, 0xBD, 0x88, 0x4A, 0xEE, 0xE0, 0xFB, 0x75, 0x7A, 0xE9, 0x4E, 0xAA, 0x97, 0x37, 0x3D }, ++ { 0xD4, 0x82, 0xB2, 0x15, 0x5D, 0x4D, 0xEC, 0x6B, 0x47, 0x36, 0xA1, 0xF1, 0x61, 0x7B, 0x53, 0xAA, 0xA3, 0x73, 0x10, 0x27, 0x7D, 0x3F, 0xEF, 0x0C, 0x37, 0xAD, 0x41, 0x76, 0x8F, 0xC2, 0x35, 0xB4 }, ++ { 0x4D, 0x41, 0x39, 0x71, 0x38, 0x7E, 0x7A, 0x88, 0x98, 0xA8, 0xDC, 0x2A, 0x27, 0x50, 0x07, 0x78, 0x53, 0x9E, 0xA2, 0x14, 0xA2, 0xDF, 0xE9, 0xB3, 0xD7, 0xE8, 0xEB, 0xDC, 0xE5, 0xCF, 0x3D, 0xB3 }, ++ { 0x69, 0x6E, 0x5D, 0x46, 0xE6, 0xC5, 0x7E, 0x87, 0x96, 0xE4, 0x73, 0x5D, 0x08, 0x91, 0x6E, 0x0B, 0x79, 0x29, 0xB3, 0xCF, 0x29, 0x8C, 0x29, 0x6D, 0x22, 0xE9, 0xD3, 0x01, 0x96, 0x53, 0x37, 0x1C }, ++ { 0x1F, 0x56, 0x47, 0xC1, 0xD3, 0xB0, 0x88, 0x22, 0x88, 0x85, 0x86, 0x5C, 0x89, 0x40, 0x90, 0x8B, 0xF4, 0x0D, 0x1A, 0x82, 0x72, 0x82, 0x19, 0x73, 0xB1, 0x60, 0x00, 0x8E, 0x7A, 0x3C, 0xE2, 0xEB }, ++ { 0xB6, 0xE7, 0x6C, 0x33, 0x0F, 0x02, 0x1A, 0x5B, 0xDA, 0x65, 0x87, 0x50, 0x10, 0xB0, 0xED, 0xF0, 0x91, 0x26, 0xC0, 0xF5, 0x10, 0xEA, 0x84, 0x90, 0x48, 0x19, 0x20, 0x03, 0xAE, 0xF4, 0xC6, 0x1C }, ++ { 0x3C, 0xD9, 0x52, 0xA0, 0xBE, 0xAD, 0xA4, 0x1A, 0xBB, 0x42, 0x4C, 0xE4, 0x7F, 0x94, 0xB4, 0x2B, 0xE6, 0x4E, 0x1F, 0xFB, 0x0F, 0xD0, 0x78, 0x22, 0x76, 0x80, 0x79, 0x46, 0xD0, 0xD0, 0xBC, 0x55 }, ++ { 0x98, 0xD9, 0x26, 0x77, 0x43, 0x9B, 0x41, 0xB7, 0xBB, 0x51, 0x33, 0x12, 0xAF, 0xB9, 0x2B, 0xCC, 0x8E, 0xE9, 0x68, 0xB2, 0xE3, 0xB2, 0x38, 0xCE, 0xCB, 0x9B, 0x0F, 0x34, 0xC9, 0xBB, 0x63, 0xD0 }, ++ { 0xEC, 0xBC, 0xA2, 0xCF, 0x08, 0xAE, 0x57, 0xD5, 0x17, 0xAD, 0x16, 0x15, 0x8A, 0x32, 0xBF, 0xA7, 0xDC, 0x03, 0x82, 0xEA, 0xED, 0xA1, 0x28, 0xE9, 0x18, 0x86, 0x73, 0x4C, 0x24, 0xA0, 0xB2, 0x9D }, ++ { 0x94, 0x2C, 0xC7, 0xC0, 0xB5, 0x2E, 0x2B, 0x16, 0xA4, 0xB8, 0x9F, 0xA4, 0xFC, 0x7E, 0x0B, 0xF6, 0x09, 0xE2, 0x9A, 0x08, 0xC1, 0xA8, 0x54, 0x34, 0x52, 0xB7, 0x7C, 0x7B, 0xFD, 0x11, 0xBB, 0x28 }, ++ { 0x8A, 0x06, 0x5D, 0x8B, 0x61, 0xA0, 0xDF, 0xFB, 0x17, 0x0D, 0x56, 0x27, 0x73, 0x5A, 0x76, 0xB0, 0xE9, 0x50, 0x60, 0x37, 0x80, 0x8C, 0xBA, 0x16, 0xC3, 0x45, 0x00, 0x7C, 0x9F, 0x79, 0xCF, 0x8F }, ++ { 0x1B, 0x9F, 0xA1, 0x97, 0x14, 0x65, 0x9C, 0x78, 0xFF, 0x41, 0x38, 0x71, 0x84, 0x92, 0x15, 0x36, 0x10, 0x29, 0xAC, 0x80, 0x2B, 0x1C, 0xBC, 0xD5, 0x4E, 0x40, 0x8B, 0xD8, 0x72, 0x87, 0xF8, 0x1F }, ++ { 0x8D, 0xAB, 0x07, 0x1B, 0xCD, 0x6C, 0x72, 0x92, 0xA9, 0xEF, 0x72, 0x7B, 0x4A, 0xE0, 0xD8, 0x67, 0x13, 0x30, 0x1D, 0xA8, 0x61, 0x8D, 0x9A, 0x48, 0xAD, 0xCE, 0x55, 0xF3, 0x03, 0xA8, 0x69, 0xA1 }, ++ { 0x82, 0x53, 0xE3, 0xE7, 0xC7, 0xB6, 0x84, 0xB9, 0xCB, 0x2B, 0xEB, 0x01, 0x4C, 0xE3, 0x30, 0xFF, 0x3D, 0x99, 0xD1, 0x7A, 0xBB, 0xDB, 0xAB, 0xE4, 0xF4, 0xD6, 0x74, 0xDE, 0xD5, 0x3F, 0xFC, 0x6B }, ++ { 0xF1, 0x95, 0xF3, 0x21, 0xE9, 0xE3, 0xD6, 0xBD, 0x7D, 0x07, 0x45, 0x04, 0xDD, 0x2A, 0xB0, 0xE6, 0x24, 0x1F, 0x92, 0xE7, 0x84, 0xB1, 0xAA, 0x27, 0x1F, 0xF6, 0x48, 0xB1, 0xCA, 0xB6, 0xD7, 0xF6 }, ++ { 0x27, 0xE4, 0xCC, 0x72, 0x09, 0x0F, 0x24, 0x12, 0x66, 0x47, 0x6A, 0x7C, 0x09, 0x49, 0x5F, 0x2D, 0xB1, 0x53, 0xD5, 0xBC, 0xBD, 0x76, 0x19, 0x03, 0xEF, 0x79, 0x27, 0x5E, 0xC5, 0x6B, 0x2E, 0xD8 }, ++ { 0x89, 0x9C, 0x24, 0x05, 0x78, 0x8E, 0x25, 0xB9, 0x9A, 0x18, 0x46, 0x35, 0x5E, 0x64, 0x6D, 0x77, 0xCF, 0x40, 0x00, 0x83, 0x41, 0x5F, 0x7D, 0xC5, 0xAF, 0xE6, 0x9D, 0x6E, 0x17, 0xC0, 0x00, 0x23 }, ++ { 0xA5, 0x9B, 0x78, 0xC4, 0x90, 0x57, 0x44, 0x07, 0x6B, 0xFE, 0xE8, 0x94, 0xDE, 0x70, 0x7D, 0x4F, 0x12, 0x0B, 0x5C, 0x68, 0x93, 0xEA, 0x04, 0x00, 0x29, 0x7D, 0x0B, 0xB8, 0x34, 0x72, 0x76, 0x32 }, ++ { 0x59, 0xDC, 0x78, 0xB1, 0x05, 0x64, 0x97, 0x07, 0xA2, 0xBB, 0x44, 0x19, 0xC4, 0x8F, 0x00, 0x54, 0x00, 0xD3, 0x97, 0x3D, 0xE3, 0x73, 0x66, 0x10, 0x23, 0x04, 0x35, 0xB1, 0x04, 0x24, 0xB2, 0x4F }, ++ { 0xC0, 0x14, 0x9D, 0x1D, 0x7E, 0x7A, 0x63, 0x53, 0xA6, 0xD9, 0x06, 0xEF, 0xE7, 0x28, 0xF2, 0xF3, 0x29, 0xFE, 0x14, 0xA4, 0x14, 0x9A, 0x3E, 0xA7, 0x76, 0x09, 0xBC, 0x42, 0xB9, 0x75, 0xDD, 0xFA }, ++ { 0xA3, 0x2F, 0x24, 0x14, 0x74, 0xA6, 0xC1, 0x69, 0x32, 0xE9, 0x24, 0x3B, 0xE0, 0xCF, 0x09, 0xBC, 0xDC, 0x7E, 0x0C, 0xA0, 0xE7, 0xA6, 0xA1, 0xB9, 0xB1, 0xA0, 0xF0, 0x1E, 0x41, 0x50, 0x23, 0x77 }, ++ { 0xB2, 0x39, 0xB2, 0xE4, 0xF8, 0x18, 0x41, 0x36, 0x1C, 0x13, 0x39, 0xF6, 0x8E, 0x2C, 0x35, 0x9F, 0x92, 0x9A, 0xF9, 0xAD, 0x9F, 0x34, 0xE0, 0x1A, 0xAB, 0x46, 0x31, 0xAD, 0x6D, 0x55, 0x00, 0xB0 }, ++ { 0x85, 0xFB, 0x41, 0x9C, 0x70, 0x02, 0xA3, 0xE0, 0xB4, 0xB6, 0xEA, 0x09, 0x3B, 0x4C, 0x1A, 0xC6, 0x93, 0x66, 0x45, 0xB6, 0x5D, 0xAC, 0x5A, 0xC1, 0x5A, 0x85, 0x28, 0xB7, 0xB9, 0x4C, 0x17, 0x54 }, ++ { 0x96, 0x19, 0x72, 0x06, 0x25, 0xF1, 0x90, 0xB9, 0x3A, 0x3F, 0xAD, 0x18, 0x6A, 0xB3, 0x14, 0x18, 0x96, 0x33, 0xC0, 0xD3, 0xA0, 0x1E, 0x6F, 0x9B, 0xC8, 0xC4, 0xA8, 0xF8, 0x2F, 0x38, 0x3D, 0xBF }, ++ { 0x7D, 0x62, 0x0D, 0x90, 0xFE, 0x69, 0xFA, 0x46, 0x9A, 0x65, 0x38, 0x38, 0x89, 0x70, 0xA1, 0xAA, 0x09, 0xBB, 0x48, 0xA2, 0xD5, 0x9B, 0x34, 0x7B, 0x97, 0xE8, 0xCE, 0x71, 0xF4, 0x8C, 0x7F, 0x46 }, ++ { 0x29, 0x43, 0x83, 0x56, 0x85, 0x96, 0xFB, 0x37, 0xC7, 0x5B, 0xBA, 0xCD, 0x97, 0x9C, 0x5F, 0xF6, 0xF2, 0x0A, 0x55, 0x6B, 0xF8, 0x87, 0x9C, 0xC7, 0x29, 0x24, 0x85, 0x5D, 0xF9, 0xB8, 0x24, 0x0E }, ++ { 0x16, 0xB1, 0x8A, 0xB3, 0x14, 0x35, 0x9C, 0x2B, 0x83, 0x3C, 0x1C, 0x69, 0x86, 0xD4, 0x8C, 0x55, 0xA9, 0xFC, 0x97, 0xCD, 0xE9, 0xA3, 0xC1, 0xF1, 0x0A, 0x31, 0x77, 0x14, 0x0F, 0x73, 0xF7, 0x38 }, ++ { 0x8C, 0xBB, 0xDD, 0x14, 0xBC, 0x33, 0xF0, 0x4C, 0xF4, 0x58, 0x13, 0xE4, 0xA1, 0x53, 0xA2, 0x73, 0xD3, 0x6A, 0xDA, 0xD5, 0xCE, 0x71, 0xF4, 0x99, 0xEE, 0xB8, 0x7F, 0xB8, 0xAC, 0x63, 0xB7, 0x29 }, ++ { 0x69, 0xC9, 0xA4, 0x98, 0xDB, 0x17, 0x4E, 0xCA, 0xEF, 0xCC, 0x5A, 0x3A, 0xC9, 0xFD, 0xED, 0xF0, 0xF8, 0x13, 0xA5, 0xBE, 0xC7, 0x27, 0xF1, 0xE7, 0x75, 0xBA, 0xBD, 0xEC, 0x77, 0x18, 0x81, 0x6E }, ++ { 0xB4, 0x62, 0xC3, 0xBE, 0x40, 0x44, 0x8F, 0x1D, 0x4F, 0x80, 0x62, 0x62, 0x54, 0xE5, 0x35, 0xB0, 0x8B, 0xC9, 0xCD, 0xCF, 0xF5, 0x99, 0xA7, 0x68, 0x57, 0x8D, 0x4B, 0x28, 0x81, 0xA8, 0xE3, 0xF0 }, ++ { 0x55, 0x3E, 0x9D, 0x9C, 0x5F, 0x36, 0x0A, 0xC0, 0xB7, 0x4A, 0x7D, 0x44, 0xE5, 0xA3, 0x91, 0xDA, 0xD4, 0xCE, 0xD0, 0x3E, 0x0C, 0x24, 0x18, 0x3B, 0x7E, 0x8E, 0xCA, 0xBD, 0xF1, 0x71, 0x5A, 0x64 }, ++ { 0x7A, 0x7C, 0x55, 0xA5, 0x6F, 0xA9, 0xAE, 0x51, 0xE6, 0x55, 0xE0, 0x19, 0x75, 0xD8, 0xA6, 0xFF, 0x4A, 0xE9, 0xE4, 0xB4, 0x86, 0xFC, 0xBE, 0x4E, 0xAC, 0x04, 0x45, 0x88, 0xF2, 0x45, 0xEB, 0xEA }, ++ { 0x2A, 0xFD, 0xF3, 0xC8, 0x2A, 0xBC, 0x48, 0x67, 0xF5, 0xDE, 0x11, 0x12, 0x86, 0xC2, 0xB3, 0xBE, 0x7D, 0x6E, 0x48, 0x65, 0x7B, 0xA9, 0x23, 0xCF, 0xBF, 0x10, 0x1A, 0x6D, 0xFC, 0xF9, 0xDB, 0x9A }, ++ { 0x41, 0x03, 0x7D, 0x2E, 0xDC, 0xDC, 0xE0, 0xC4, 0x9B, 0x7F, 0xB4, 0xA6, 0xAA, 0x09, 0x99, 0xCA, 0x66, 0x97, 0x6C, 0x74, 0x83, 0xAF, 0xE6, 0x31, 0xD4, 0xED, 0xA2, 0x83, 0x14, 0x4F, 0x6D, 0xFC }, ++ { 0xC4, 0x46, 0x6F, 0x84, 0x97, 0xCA, 0x2E, 0xEB, 0x45, 0x83, 0xA0, 0xB0, 0x8E, 0x9D, 0x9A, 0xC7, 0x43, 0x95, 0x70, 0x9F, 0xDA, 0x10, 0x9D, 0x24, 0xF2, 0xE4, 0x46, 0x21, 0x96, 0x77, 0x9C, 0x5D }, ++ { 0x75, 0xF6, 0x09, 0x33, 0x8A, 0xA6, 0x7D, 0x96, 0x9A, 0x2A, 0xE2, 0xA2, 0x36, 0x2B, 0x2D, 0xA9, 0xD7, 0x7C, 0x69, 0x5D, 0xFD, 0x1D, 0xF7, 0x22, 0x4A, 0x69, 0x01, 0xDB, 0x93, 0x2C, 0x33, 0x64 }, ++ { 0x68, 0x60, 0x6C, 0xEB, 0x98, 0x9D, 0x54, 0x88, 0xFC, 0x7C, 0xF6, 0x49, 0xF3, 0xD7, 0xC2, 0x72, 0xEF, 0x05, 0x5D, 0xA1, 0xA9, 0x3F, 0xAE, 0xCD, 0x55, 0xFE, 0x06, 0xF6, 0x96, 0x70, 0x98, 0xCA }, ++ { 0x44, 0x34, 0x6B, 0xDE, 0xB7, 0xE0, 0x52, 0xF6, 0x25, 0x50, 0x48, 0xF0, 0xD9, 0xB4, 0x2C, 0x42, 0x5B, 0xAB, 0x9C, 0x3D, 0xD2, 0x41, 0x68, 0x21, 0x2C, 0x3E, 0xCF, 0x1E, 0xBF, 0x34, 0xE6, 0xAE }, ++ { 0x8E, 0x9C, 0xF6, 0xE1, 0xF3, 0x66, 0x47, 0x1F, 0x2A, 0xC7, 0xD2, 0xEE, 0x9B, 0x5E, 0x62, 0x66, 0xFD, 0xA7, 0x1F, 0x8F, 0x2E, 0x41, 0x09, 0xF2, 0x23, 0x7E, 0xD5, 0xF8, 0x81, 0x3F, 0xC7, 0x18 }, ++ { 0x84, 0xBB, 0xEB, 0x84, 0x06, 0xD2, 0x50, 0x95, 0x1F, 0x8C, 0x1B, 0x3E, 0x86, 0xA7, 0xC0, 0x10, 0x08, 0x29, 0x21, 0x83, 0x3D, 0xFD, 0x95, 0x55, 0xA2, 0xF9, 0x09, 0xB1, 0x08, 0x6E, 0xB4, 0xB8 }, ++ { 0xEE, 0x66, 0x6F, 0x3E, 0xEF, 0x0F, 0x7E, 0x2A, 0x9C, 0x22, 0x29, 0x58, 0xC9, 0x7E, 0xAF, 0x35, 0xF5, 0x1C, 0xED, 0x39, 0x3D, 0x71, 0x44, 0x85, 0xAB, 0x09, 0xA0, 0x69, 0x34, 0x0F, 0xDF, 0x88 }, ++ { 0xC1, 0x53, 0xD3, 0x4A, 0x65, 0xC4, 0x7B, 0x4A, 0x62, 0xC5, 0xCA, 0xCF, 0x24, 0x01, 0x09, 0x75, 0xD0, 0x35, 0x6B, 0x2F, 0x32, 0xC8, 0xF5, 0xDA, 0x53, 0x0D, 0x33, 0x88, 0x16, 0xAD, 0x5D, 0xE6 }, ++ { 0x9F, 0xC5, 0x45, 0x01, 0x09, 0xE1, 0xB7, 0x79, 0xF6, 0xC7, 0xAE, 0x79, 0xD5, 0x6C, 0x27, 0x63, 0x5C, 0x8D, 0xD4, 0x26, 0xC5, 0xA9, 0xD5, 0x4E, 0x25, 0x78, 0xDB, 0x98, 0x9B, 0x8C, 0x3B, 0x4E }, ++ { 0xD1, 0x2B, 0xF3, 0x73, 0x2E, 0xF4, 0xAF, 0x5C, 0x22, 0xFA, 0x90, 0x35, 0x6A, 0xF8, 0xFC, 0x50, 0xFC, 0xB4, 0x0F, 0x8F, 0x2E, 0xA5, 0xC8, 0x59, 0x47, 0x37, 0xA3, 0xB3, 0xD5, 0xAB, 0xDB, 0xD7 }, ++ { 0x11, 0x03, 0x0B, 0x92, 0x89, 0xBB, 0xA5, 0xAF, 0x65, 0x26, 0x06, 0x72, 0xAB, 0x6F, 0xEE, 0x88, 0xB8, 0x74, 0x20, 0xAC, 0xEF, 0x4A, 0x17, 0x89, 0xA2, 0x07, 0x3B, 0x7E, 0xC2, 0xF2, 0xA0, 0x9E }, ++ { 0x69, 0xCB, 0x19, 0x2B, 0x84, 0x44, 0x00, 0x5C, 0x8C, 0x0C, 0xEB, 0x12, 0xC8, 0x46, 0x86, 0x07, 0x68, 0x18, 0x8C, 0xDA, 0x0A, 0xEC, 0x27, 0xA9, 0xC8, 0xA5, 0x5C, 0xDE, 0xE2, 0x12, 0x36, 0x32 }, ++ { 0xDB, 0x44, 0x4C, 0x15, 0x59, 0x7B, 0x5F, 0x1A, 0x03, 0xD1, 0xF9, 0xED, 0xD1, 0x6E, 0x4A, 0x9F, 0x43, 0xA6, 0x67, 0xCC, 0x27, 0x51, 0x75, 0xDF, 0xA2, 0xB7, 0x04, 0xE3, 0xBB, 0x1A, 0x9B, 0x83 }, ++ { 0x3F, 0xB7, 0x35, 0x06, 0x1A, 0xBC, 0x51, 0x9D, 0xFE, 0x97, 0x9E, 0x54, 0xC1, 0xEE, 0x5B, 0xFA, 0xD0, 0xA9, 0xD8, 0x58, 0xB3, 0x31, 0x5B, 0xAD, 0x34, 0xBD, 0xE9, 0x99, 0xEF, 0xD7, 0x24, 0xDD } ++}; ++ ++bool blake2s_selftest(void) ++{ ++ u8 key[BLAKE2S_KEYBYTES]; ++ u8 buf[ARRAY_SIZE(blake2s_testvecs)]; ++ u8 hash[BLAKE2S_OUTBYTES]; ++ size_t i; ++ bool success = true; ++ ++ for (i = 0; i < BLAKE2S_KEYBYTES; ++i) ++ key[i] = (u8)i; ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i) ++ buf[i] = (u8)i; ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_keyed_testvecs); ++i) { ++ blake2s(hash, buf, key, BLAKE2S_OUTBYTES, i, BLAKE2S_KEYBYTES); ++ if (memcmp(hash, blake2s_keyed_testvecs[i], BLAKE2S_OUTBYTES)) { ++ pr_info("blake2s keyed self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(blake2s_testvecs); ++i) { ++ blake2s(hash, buf, NULL, BLAKE2S_OUTBYTES, i, 0); ++ if (memcmp(hash, blake2s_testvecs[i], BLAKE2S_OUTBYTES)) { ++ pr_info("blake2s unkeyed self-test %zu: FAIL\n", i + i); ++ success = false; ++ } ++ } ++ ++ if (success) ++ pr_info("blake2s self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/chacha20poly1305.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++/* ChaCha20-Poly1305 AEAD test vectors from RFC7539 2.8.2 */ ++struct chacha20poly1305_testvec { ++ u8 *key, *nonce, *assoc, *input, *result; ++ size_t alen, ilen; ++}; ++static const struct chacha20poly1305_testvec chacha20poly1305_enc_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x01\x02\x03\x04\x05\x06\x07\x08", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d", ++ .ilen = 265, ++ .result = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38" ++} }; ++static const struct chacha20poly1305_testvec chacha20poly1305_dec_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x01\x02\x03\x04\x05\x06\x07\x08", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x64\xa0\x86\x15\x75\x86\x1a\xf4\x60\xf0\x62\xc7\x9b\xe6\x43\xbd\x5e\x80\x5c\xfd\x34\x5c\xf3\x89\xf1\x08\x67\x0a\xc7\x6c\x8c\xb2\x4c\x6c\xfc\x18\x75\x5d\x43\xee\xa0\x9e\xe9\x4e\x38\x2d\x26\xb0\xbd\xb7\xb7\x3c\x32\x1b\x01\x00\xd4\xf0\x3b\x7f\x35\x58\x94\xcf\x33\x2f\x83\x0e\x71\x0b\x97\xce\x98\xc8\xa8\x4a\xbd\x0b\x94\x81\x14\xad\x17\x6e\x00\x8d\x33\xbd\x60\xf9\x82\xb1\xff\x37\xc8\x55\x97\x97\xa0\x6e\xf4\xf0\xef\x61\xc1\x86\x32\x4e\x2b\x35\x06\x38\x36\x06\x90\x7b\x6a\x7c\x02\xb0\xf9\xf6\x15\x7b\x53\xc8\x67\xe4\xb9\x16\x6c\x76\x7b\x80\x4d\x46\xa5\x9b\x52\x16\xcd\xe7\xa4\xe9\x90\x40\xc5\xa4\x04\x33\x22\x5e\xe2\x82\xa1\xb0\xa0\x6c\x52\x3e\xaf\x45\x34\xd7\xf8\x3f\xa1\x15\x5b\x00\x47\x71\x8c\xbc\x54\x6a\x0d\x07\x2b\x04\xb3\x56\x4e\xea\x1b\x42\x22\x73\xf5\x48\x27\x1a\x0b\xb2\x31\x60\x53\xfa\x76\x99\x19\x55\xeb\xd6\x31\x59\x43\x4e\xce\xbb\x4e\x46\x6d\xae\x5a\x10\x73\xa6\x72\x76\x27\x09\x7a\x10\x49\xe6\x17\xd9\x1d\x36\x10\x94\xfa\x68\xf0\xff\x77\x98\x71\x30\x30\x5b\xea\xba\x2e\xda\x04\xdf\x99\x7b\x71\x4d\x6c\x6f\x2c\x29\xa6\xad\x5c\xb4\x02\x2b\x02\x70\x9b\xee\xad\x9d\x67\x89\x0c\xbb\x22\x39\x23\x36\xfe\xa1\x85\x1f\x38", ++ .ilen = 281, ++ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d" ++} }; ++ ++static const struct chacha20poly1305_testvec xchacha20poly1305_enc_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d", ++ .ilen = 265, ++ .result = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c" ++} }; ++static const struct chacha20poly1305_testvec xchacha20poly1305_dec_vectors[] = { { ++ .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a\xf3\x33\x88\x86\x04\xf6\xb5\xf0\x47\x39\x17\xc1\x40\x2b\x80\x09\x9d\xca\x5c\xbc\x20\x70\x75\xc0", ++ .nonce = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17", ++ .assoc = "\xf3\x33\x88\x86\x00\x00\x00\x00\x00\x00\x4e\x91", ++ .alen = 12, ++ .input = "\x1a\x6e\x3a\xd9\xfd\x41\x3f\x77\x54\x72\x0a\x70\x9a\xa0\x29\x92\x2e\xed\x93\xcf\x0f\x71\x88\x18\x7a\x9d\x2d\x24\xe0\xf5\xea\x3d\x55\x64\xd7\xad\x2a\x1a\x1f\x7e\x86\x6d\xb0\xce\x80\x41\x72\x86\x26\xee\x84\xd7\xef\x82\x9e\xe2\x60\x9d\x5a\xfc\xf0\xe4\x19\x85\xea\x09\xc6\xfb\xb3\xa9\x50\x09\xec\x5e\x11\x90\xa1\xc5\x4e\x49\xef\x50\xd8\x8f\xe0\x78\xd7\xfd\xb9\x3b\xc9\xf2\x91\xc8\x25\xc8\xa7\x63\x60\xce\x10\xcd\xc6\x7f\xf8\x16\xf8\xe1\x0a\xd9\xde\x79\x50\x33\xf2\x16\x0f\x17\xba\xb8\x5d\xd8\xdf\x4e\x51\xa8\x39\xd0\x85\xca\x46\x6a\x10\xa7\xa3\x88\xef\x79\xb9\xf8\x24\xf3\xe0\x71\x7b\x76\x28\x46\x3a\x3a\x1b\x91\xb6\xd4\x3e\x23\xe5\x44\x15\xbf\x60\x43\x9d\xa4\xbb\xd5\x5f\x89\xeb\xef\x8e\xfd\xdd\xb4\x0d\x46\xf0\x69\x23\x63\xae\x94\xf5\x5e\xa5\xad\x13\x1c\x41\x76\xe6\x90\xd6\x6d\xa2\x8f\x97\x4c\xa8\x0b\xcf\x8d\x43\x2b\x9c\x9b\xc5\x58\xa5\xb6\x95\x9a\xbf\x81\xc6\x54\xc9\x66\x0c\xe5\x4f\x6a\x53\xa1\xe5\x0c\xba\x31\xde\x34\x64\x73\x8a\x3b\xbd\x92\x01\xdb\x71\x69\xf3\x58\x99\xbc\xd1\xcb\x4a\x05\xe2\x58\x9c\x25\x17\xcd\xdc\x83\xb7\xff\xfb\x09\x61\xad\xbf\x13\x5b\x5e\xed\x46\x82\x6f\x22\xd8\x93\xa6\x85\x5b\x40\x39\x5c\xc5\x9c", ++ .ilen = 281, ++ .result = "\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x72\x65\x20\x64\x72\x61\x66\x74\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x76\x61\x6c\x69\x64\x20\x66\x6f\x72\x20\x61\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6f\x66\x20\x73\x69\x78\x20\x6d\x6f\x6e\x74\x68\x73\x20\x61\x6e\x64\x20\x6d\x61\x79\x20\x62\x65\x20\x75\x70\x64\x61\x74\x65\x64\x2c\x20\x72\x65\x70\x6c\x61\x63\x65\x64\x2c\x20\x6f\x72\x20\x6f\x62\x73\x6f\x6c\x65\x74\x65\x64\x20\x62\x79\x20\x6f\x74\x68\x65\x72\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x73\x20\x61\x74\x20\x61\x6e\x79\x20\x74\x69\x6d\x65\x2e\x20\x49\x74\x20\x69\x73\x20\x69\x6e\x61\x70\x70\x72\x6f\x70\x72\x69\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x49\x6e\x74\x65\x72\x6e\x65\x74\x2d\x44\x72\x61\x66\x74\x73\x20\x61\x73\x20\x72\x65\x66\x65\x72\x65\x6e\x63\x65\x20\x6d\x61\x74\x65\x72\x69\x61\x6c\x20\x6f\x72\x20\x74\x6f\x20\x63\x69\x74\x65\x20\x74\x68\x65\x6d\x20\x6f\x74\x68\x65\x72\x20\x74\x68\x61\x6e\x20\x61\x73\x20\x2f\xe2\x80\x9c\x77\x6f\x72\x6b\x20\x69\x6e\x20\x70\x72\x6f\x67\x72\x65\x73\x73\x2e\x2f\xe2\x80\x9d" ++} }; ++ ++bool chacha20poly1305_selftest(void) ++{ ++ size_t i; ++ u8 computed_result[512]; ++ bool success = true; ++ ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_enc_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = chacha20poly1305_encrypt(computed_result, chacha20poly1305_enc_vectors[i].input, chacha20poly1305_enc_vectors[i].ilen, chacha20poly1305_enc_vectors[i].assoc, chacha20poly1305_enc_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_enc_vectors[i].nonce), chacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_result, chacha20poly1305_enc_vectors[i].result, chacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) { ++ pr_info("chacha20poly1305 encryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(chacha20poly1305_dec_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = chacha20poly1305_decrypt(computed_result, chacha20poly1305_dec_vectors[i].input, chacha20poly1305_dec_vectors[i].ilen, chacha20poly1305_dec_vectors[i].assoc, chacha20poly1305_dec_vectors[i].alen, le64_to_cpu(*(__force __le64 *)chacha20poly1305_dec_vectors[i].nonce), chacha20poly1305_dec_vectors[i].key); ++ if (!success || memcmp(computed_result, chacha20poly1305_dec_vectors[i].result, chacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) { ++ pr_info("chacha20poly1305 decryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_enc_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = xchacha20poly1305_encrypt(computed_result, xchacha20poly1305_enc_vectors[i].input, xchacha20poly1305_enc_vectors[i].ilen, xchacha20poly1305_enc_vectors[i].assoc, xchacha20poly1305_enc_vectors[i].alen, xchacha20poly1305_enc_vectors[i].nonce, xchacha20poly1305_enc_vectors[i].key); ++ if (memcmp(computed_result, xchacha20poly1305_enc_vectors[i].result, xchacha20poly1305_enc_vectors[i].ilen + POLY1305_MAC_SIZE)) { ++ pr_info("xchacha20poly1305 encryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ for (i = 0; i < ARRAY_SIZE(xchacha20poly1305_dec_vectors); ++i) { ++ memset(computed_result, 0, sizeof(computed_result)); ++ success = xchacha20poly1305_decrypt(computed_result, xchacha20poly1305_dec_vectors[i].input, xchacha20poly1305_dec_vectors[i].ilen, xchacha20poly1305_dec_vectors[i].assoc, xchacha20poly1305_dec_vectors[i].alen, xchacha20poly1305_dec_vectors[i].nonce, xchacha20poly1305_dec_vectors[i].key); ++ if (!success || memcmp(computed_result, xchacha20poly1305_dec_vectors[i].result, xchacha20poly1305_dec_vectors[i].ilen - POLY1305_MAC_SIZE)) { ++ pr_info("xchacha20poly1305 decryption self-test %zu: FAIL\n", i + 1); ++ success = false; ++ } ++ } ++ if (success) ++ pr_info("chacha20poly1305 self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/counter.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++bool packet_counter_selftest(void) ++{ ++ bool success = true; ++ unsigned int test_num = 0, i; ++ union noise_counter counter; ++ ++#define T_INIT do { memset(&counter, 0, sizeof(union noise_counter)); spin_lock_init(&counter.receive.lock); } while (0) ++#define T_LIM (COUNTER_WINDOW_SIZE + 1) ++#define T(n, v) do { ++test_num; if (counter_validate(&counter, n) != v) { pr_info("nonce counter self-test %u: FAIL\n", test_num); success = false; } } while (0) ++ T_INIT; ++ /* 1 */ T(0, true); ++ /* 2 */ T(1, true); ++ /* 3 */ T(1, false); ++ /* 4 */ T(9, true); ++ /* 5 */ T(8, true); ++ /* 6 */ T(7, true); ++ /* 7 */ T(7, false); ++ /* 8 */ T(T_LIM, true); ++ /* 9 */ T(T_LIM - 1, true); ++ /* 10 */ T(T_LIM - 1, false); ++ /* 11 */ T(T_LIM - 2, true); ++ /* 12 */ T(2, true); ++ /* 13 */ T(2, false); ++ /* 14 */ T(T_LIM + 16, true); ++ /* 15 */ T(3, false); ++ /* 16 */ T(T_LIM + 16, false); ++ /* 17 */ T(T_LIM * 4, true); ++ /* 18 */ T(T_LIM * 4 - (T_LIM - 1), true); ++ /* 19 */ T(10, false); ++ /* 20 */ T(T_LIM * 4 - T_LIM, false); ++ /* 21 */ T(T_LIM * 4 - (T_LIM + 1), false); ++ /* 22 */ T(T_LIM * 4 - (T_LIM - 2), true); ++ /* 23 */ T(T_LIM * 4 + 1 - T_LIM, false); ++ /* 24 */ T(0, false); ++ /* 25 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 26 */ T(REJECT_AFTER_MESSAGES - 1, true); ++ /* 27 */ T(REJECT_AFTER_MESSAGES, false); ++ /* 28 */ T(REJECT_AFTER_MESSAGES - 1, false); ++ /* 29 */ T(REJECT_AFTER_MESSAGES - 2, true); ++ /* 30 */ T(REJECT_AFTER_MESSAGES + 1, false); ++ /* 31 */ T(REJECT_AFTER_MESSAGES + 2, false); ++ /* 32 */ T(REJECT_AFTER_MESSAGES - 2, false); ++ /* 33 */ T(REJECT_AFTER_MESSAGES - 3, true); ++ /* 34 */ T(0, false); ++ ++ T_INIT; ++ for (i = 1; i <= COUNTER_WINDOW_SIZE; ++i) ++ T(i, true); ++ T(0, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = 2; i <= COUNTER_WINDOW_SIZE + 1; ++i) ++ T(i, true); ++ T(1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 0 ;) ++ T(i, true); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 2; i-- > 1 ;) ++ T(i, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;) ++ T(i, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++ T(0, false); ++ ++ T_INIT; ++ for (i = COUNTER_WINDOW_SIZE + 1; i-- > 1 ;) ++ T(i, true); ++ T(0, true); ++ T(COUNTER_WINDOW_SIZE + 1, true); ++#undef T ++#undef T_LIM ++#undef T_INIT ++ ++ if (success) ++ pr_info("nonce counter self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/curve25519.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,66 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++struct curve25519_test_vector { ++ u8 private[CURVE25519_POINT_SIZE]; ++ u8 public[CURVE25519_POINT_SIZE]; ++ u8 result[CURVE25519_POINT_SIZE]; ++}; ++static const struct curve25519_test_vector curve25519_test_vectors[] = { ++ { ++ .private = { 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a }, ++ .public = { 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 } ++ }, ++ { ++ .private = { 0x5d, 0xab, 0x08, 0x7e, 0x62, 0x4a, 0x8a, 0x4b, 0x79, 0xe1, 0x7f, 0x8b, 0x83, 0x80, 0x0e, 0xe6, 0x6f, 0x3b, 0xb1, 0x29, 0x26, 0x18, 0xb6, 0xfd, 0x1c, 0x2f, 0x8b, 0x27, 0xff, 0x88, 0xe0, 0xeb }, ++ .public = { 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a }, ++ .result = { 0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42 } ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, ++ .result = { 0x3c, 0x77, 0x77, 0xca, 0xf9, 0x97, 0xb2, 0x64, 0x41, 0x60, 0x77, 0x66, 0x5b, 0x4e, 0x22, 0x9d, 0xb, 0x95, 0x48, 0xdc, 0xc, 0xd8, 0x19, 0x98, 0xdd, 0xcd, 0xc5, 0xc8, 0x53, 0x3c, 0x79, 0x7f } ++ }, ++ { ++ .private = { 1 }, ++ .public = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, ++ .result = { 0xb3, 0x2d, 0x13, 0x62, 0xc2, 0x48, 0xd6, 0x2f, 0xe6, 0x26, 0x19, 0xcf, 0xf0, 0x4d, 0xd4, 0x3d, 0xb7, 0x3f, 0xfc, 0x1b, 0x63, 0x8, 0xed, 0xe3, 0xb, 0x78, 0xd8, 0x73, 0x80, 0xf1, 0xe8, 0x34 } ++ }, ++ { ++ .private = { 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 }, ++ .public = { 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c }, ++ .result = { 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 } ++ }, ++ { ++ .private = { 1, 2, 3, 4 }, ++ .public = { 0 }, ++ .result = { 0 } ++ }, ++ { ++ .private = { 2, 4, 6, 8 }, ++ .public = { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8 }, ++ .result = { 0 } ++ } ++}; ++bool curve25519_selftest(void) ++{ ++ bool success = true; ++ size_t i = 0; ++ u8 out[CURVE25519_POINT_SIZE]; ++ ++ for (i = 0; i < ARRAY_SIZE(curve25519_test_vectors); ++i) { ++ memset(out, 0, CURVE25519_POINT_SIZE); ++ curve25519(out, curve25519_test_vectors[i].private, curve25519_test_vectors[i].public); ++ if (memcmp(out, curve25519_test_vectors[i].result, CURVE25519_POINT_SIZE)) { ++ pr_info("curve25519 self-test %zu: FAIL\n", i + 1); ++ success = false; ++ break; ++ } ++ } ++ ++ if (success) ++ pr_info("curve25519 self-tests: pass\n"); ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/routing-table.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,133 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifdef DEBUG ++static inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d) ++{ ++ static struct in_addr ip; ++ u8 *split = (u8 *)&ip; ++ split[0] = a; ++ split[1] = b; ++ split[2] = c; ++ split[3] = d; ++ return &ip; ++} ++static inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d) ++{ ++ static struct in6_addr ip; ++ __be32 *split = (__be32 *)&ip; ++ split[0] = cpu_to_be32(a); ++ split[1] = cpu_to_be32(b); ++ split[2] = cpu_to_be32(c); ++ split[3] = cpu_to_be32(d); ++ return &ip; ++} ++ ++bool routing_table_selftest(void) ++{ ++ struct routing_table t; ++ struct wireguard_peer *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL, *g = NULL, *h = NULL; ++ size_t i = 0; ++ bool success = false; ++ struct in6_addr ip; ++ __be64 part; ++ ++ routing_table_init(&t); ++#define init_peer(name) do { name = kzalloc(sizeof(struct wireguard_peer), GFP_KERNEL); if (!name) goto free; kref_init(&name->refcount); } while (0) ++ init_peer(a); ++ init_peer(b); ++ init_peer(c); ++ init_peer(d); ++ init_peer(e); ++ init_peer(f); ++ init_peer(g); ++ init_peer(h); ++#undef init_peer ++ ++#define insert(version, mem, ipa, ipb, ipc, ipd, cidr) routing_table_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), cidr, mem) ++ insert(4, a, 192, 168, 4, 0, 24); ++ insert(4, b, 192, 168, 4, 4, 32); ++ insert(4, c, 192, 168, 0, 0, 16); ++ insert(4, d, 192, 95, 5, 64, 27); ++ insert(4, c, 192, 95, 5, 65, 27); /* replaces previous entry, and maskself is required */ ++ insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128); ++ insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64); ++ insert(4, e, 0, 0, 0, 0, 0); ++ insert(6, e, 0, 0, 0, 0, 0); ++ insert(6, f, 0, 0, 0, 0, 0); /* replaces previous entry */ ++ insert(6, g, 0x24046800, 0, 0, 0, 32); ++ insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64); /* maskself is required */ ++ insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128); ++ insert(4, g, 64, 15, 112, 0, 20); ++ insert(4, h, 64, 15, 123, 211, 25); /* maskself is required */ ++ insert(4, a, 10, 0, 0, 0, 25); ++ insert(4, b, 10, 0, 0, 128, 25); ++ insert(4, a, 10, 1, 0, 0, 30); ++ insert(4, b, 10, 1, 0, 4, 30); ++ insert(4, c, 10, 1, 0, 8, 29); ++ insert(4, d, 10, 1, 0, 16, 29); ++#undef insert ++ ++ success = true; ++#define test(version, mem, ipa, ipb, ipc, ipd) do { \ ++ bool _s = routing_table_lookup_v##version(&t, ip##version(ipa, ipb, ipc, ipd)) == mem; \ ++ ++i; \ ++ if (!_s) { \ ++ pr_info("routing table self-test %zu: FAIL\n", i); \ ++ success = false; \ ++ } \ ++} while (0) ++ test(4, a, 192, 168, 4, 20); ++ test(4, a, 192, 168, 4, 0); ++ test(4, b, 192, 168, 4, 4); ++ test(4, c, 192, 168, 200, 182); ++ test(4, c, 192, 95, 5, 68); ++ test(4, e, 192, 95, 5, 96); ++ test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543); ++ test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee); ++ test(6, f, 0x26075300, 0x60006b01, 0, 0); ++ test(6, g, 0x24046800, 0x40040806, 0, 0x1006); ++ test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678); ++ test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678); ++ test(6, h, 0x24046800, 0x40040800, 0, 0); ++ test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010); ++ test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef); ++ test(4, g, 64, 15, 116, 26); ++ test(4, g, 64, 15, 127, 3); ++ test(4, g, 64, 15, 123, 1); ++ test(4, h, 64, 15, 123, 128); ++ test(4, h, 64, 15, 123, 129); ++ test(4, a, 10, 0, 0, 52); ++ test(4, b, 10, 0, 0, 220); ++ test(4, a, 10, 1, 0, 2); ++ test(4, b, 10, 1, 0, 6); ++ test(4, c, 10, 1, 0, 10); ++ test(4, d, 10, 1, 0, 20); ++#undef test ++ ++ /* These will hit the BUG_ON(len >= 128) in free_node if something goes wrong. */ ++ for (i = 0; i < 128; ++i) { ++ part = cpu_to_be64(~(1LLU << (i % 64))); ++ memset(&ip, 0xff, 16); ++ memcpy((u8 *)&ip + (i < 64) * 8, &part, 8); ++ routing_table_insert_v6(&t, &ip, 128, a); ++ } ++ ++ if (success) ++ pr_info("routing table self-tests: pass\n"); ++ ++free: ++ routing_table_free(&t); ++ kfree(a); ++ kfree(b); ++ kfree(c); ++ kfree(d); ++ kfree(e); ++ kfree(f); ++ kfree(g); ++ kfree(h); ++ ++ return success; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/selftest/siphash.h 2017-03-05 17:03:41.528682420 +0200 +@@ -0,0 +1,89 @@ ++/* Test cases for siphash.c ++ * ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4. ++ */ ++ ++#ifdef DEBUG ++ ++#include ++#include ++#include ++#include ++ ++/* Test vectors taken from official reference source available at: ++ * https://131002.net/siphash/siphash24.c ++ */ ++static const u64 test_vectors[64] = { ++ 0x726fdb47dd0e0e31ULL, 0x74f839c593dc67fdULL, 0x0d6c8009d9a94f5aULL, ++ 0x85676696d7fb7e2dULL, 0xcf2794e0277187b7ULL, 0x18765564cd99a68dULL, ++ 0xcbc9466e58fee3ceULL, 0xab0200f58b01d137ULL, 0x93f5f5799a932462ULL, ++ 0x9e0082df0ba9e4b0ULL, 0x7a5dbbc594ddb9f3ULL, 0xf4b32f46226bada7ULL, ++ 0x751e8fbc860ee5fbULL, 0x14ea5627c0843d90ULL, 0xf723ca908e7af2eeULL, ++ 0xa129ca6149be45e5ULL, 0x3f2acc7f57c29bdbULL, 0x699ae9f52cbe4794ULL, ++ 0x4bc1b3f0968dd39cULL, 0xbb6dc91da77961bdULL, 0xbed65cf21aa2ee98ULL, ++ 0xd0f2cbb02e3b67c7ULL, 0x93536795e3a33e88ULL, 0xa80c038ccd5ccec8ULL, ++ 0xb8ad50c6f649af94ULL, 0xbce192de8a85b8eaULL, 0x17d835b85bbb15f3ULL, ++ 0x2f2e6163076bcfadULL, 0xde4daaaca71dc9a5ULL, 0xa6a2506687956571ULL, ++ 0xad87a3535c49ef28ULL, 0x32d892fad841c342ULL, 0x7127512f72f27cceULL, ++ 0xa7f32346f95978e3ULL, 0x12e0b01abb051238ULL, 0x15e034d40fa197aeULL, ++ 0x314dffbe0815a3b4ULL, 0x027990f029623981ULL, 0xcadcd4e59ef40c4dULL, ++ 0x9abfd8766a33735cULL, 0x0e3ea96b5304a7d0ULL, 0xad0c42d6fc585992ULL, ++ 0x187306c89bc215a9ULL, 0xd4a60abcf3792b95ULL, 0xf935451de4f21df2ULL, ++ 0xa9538f0419755787ULL, 0xdb9acddff56ca510ULL, 0xd06c98cd5c0975ebULL, ++ 0xe612a3cb9ecba951ULL, 0xc766e62cfcadaf96ULL, 0xee64435a9752fe72ULL, ++ 0xa192d576b245165aULL, 0x0a8787bf8ecb74b2ULL, 0x81b3e73d20b49b6fULL, ++ 0x7fa8220ba3b2eceaULL, 0x245731c13ca42499ULL, 0xb78dbfaf3a8d83bdULL, ++ 0xea1ad565322a1a0bULL, 0x60e61c23a3795013ULL, 0x6606d7e446282b93ULL, ++ 0x6ca4ecb15c5f91e1ULL, 0x9f626da15c9625f3ULL, 0xe51b38608ef25f57ULL, ++ 0x958a324ceb064572ULL ++}; ++static const siphash_key_t test_key = ++ { 0x0706050403020100ULL , 0x0f0e0d0c0b0a0908ULL }; ++ ++bool siphash_selftest(void) ++{ ++ u8 in[64] __aligned(SIPHASH_ALIGNMENT); ++ u8 in_unaligned[65]; ++ u8 i; ++ bool ret = true; ++ ++ for (i = 0; i < 64; ++i) { ++ in[i] = i; ++ in_unaligned[i + 1] = i; ++ if (siphash(in, i, test_key) != test_vectors[i]) { ++ pr_info("siphash self-test aligned %u: FAIL\n", i + 1); ++ ret = false; ++ } ++ if (siphash(in_unaligned + 1, i, test_key) != test_vectors[i]) { ++ pr_info("siphash self-test unaligned %u: FAIL\n", i + 1); ++ ret = false; ++ } ++ } ++ if (siphash_1u64(0x0706050403020100ULL, test_key) != test_vectors[8]) { ++ pr_info("siphash self-test 1u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_2u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, test_key) != test_vectors[16]) { ++ pr_info("siphash self-test 2u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_3u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, ++ 0x1716151413121110ULL, test_key) != test_vectors[24]) { ++ pr_info("siphash self-test 3u64: FAIL\n"); ++ ret = false; ++ } ++ if (siphash_4u64(0x0706050403020100ULL, 0x0f0e0d0c0b0a0908ULL, ++ 0x1716151413121110ULL, 0x1f1e1d1c1b1a1918ULL, test_key) != test_vectors[32]) { ++ pr_info("siphash self-test 4u64: FAIL\n"); ++ ret = false; ++ } ++ if (ret) ++ pr_info("siphash self-tests: pass\n"); ++ return ret; ++} ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/blake2s.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,278 @@ ++/* Original author: Samuel Neves ++ * ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "blake2s.h" ++ ++#include ++#include ++#include ++ ++typedef struct { ++ u8 digest_length; ++ u8 key_length; ++ u8 fanout; ++ u8 depth; ++ u32 leaf_length; ++ u8 node_offset[6]; ++ u8 node_depth; ++ u8 inner_length; ++ u8 salt[8]; ++ u8 personal[8]; ++} __packed blake2s_param; ++ ++static const u32 blake2s_iv[8] = { ++ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, ++ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL ++}; ++ ++static const u8 blake2s_sigma[10][16] = { ++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, ++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, ++ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, ++ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, ++ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, ++ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, ++ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, ++ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, ++ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, ++ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, ++}; ++ ++static inline u32 le32_to_cpuvp(const void *p) ++{ ++ return le32_to_cpup(p); ++} ++ ++static inline void blake2s_set_lastblock(struct blake2s_state *state) ++{ ++ if (state->last_node) ++ state->f[1] = -1; ++ state->f[0] = -1; ++} ++ ++static inline void blake2s_increment_counter(struct blake2s_state *state, const u32 inc) ++{ ++ state->t[0] += inc; ++ state->t[1] += (state->t[0] < inc); ++} ++ ++static inline void blake2s_init_param(struct blake2s_state *state, const blake2s_param *param) ++{ ++ const u32 *p; ++ int i; ++ memset(state, 0, sizeof(struct blake2s_state)); ++ for (i = 0; i < 8; ++i) ++ state->h[i] = blake2s_iv[i]; ++ p = (const u32 *)param; ++ /* IV XOR ParamBlock */ ++ for (i = 0; i < 8; ++i) ++ state->h[i] ^= le32_to_cpuvp(&p[i]); ++} ++ ++void blake2s_init(struct blake2s_state *state, const u8 outlen) ++{ ++ blake2s_param param = { ++ .digest_length = outlen, ++ .fanout = 1, ++ .depth = 1 ++ }; ++ ++#ifdef DEBUG ++ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES); ++#endif ++ blake2s_init_param(state, ¶m); ++} ++ ++void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen) ++{ ++ blake2s_param param = { ++ .digest_length = outlen, ++ .key_length = keylen, ++ .fanout = 1, ++ .depth = 1 ++ }; ++ u8 block[BLAKE2S_BLOCKBYTES] = { 0 }; ++ ++#ifdef DEBUG ++ BUG_ON(!outlen || outlen > BLAKE2S_OUTBYTES || !key || !keylen || keylen > BLAKE2S_KEYBYTES); ++#endif ++ blake2s_init_param(state, ¶m); ++ memcpy(block, key, keylen); ++ blake2s_update(state, block, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(block, BLAKE2S_BLOCKBYTES); ++} ++ ++static inline void blake2s_compress(struct blake2s_state *state, const u8 block[BLAKE2S_BLOCKBYTES]) ++{ ++ u32 m[16]; ++ u32 v[16]; ++ int i; ++ ++ for (i = 0; i < 16; ++i) ++ m[i] = le32_to_cpuvp(block + i * sizeof(m[i])); ++ ++ for (i = 0; i < 8; ++i) ++ v[i] = state->h[i]; ++ ++ v[8] = blake2s_iv[0]; ++ v[9] = blake2s_iv[1]; ++ v[10] = blake2s_iv[2]; ++ v[11] = blake2s_iv[3]; ++ v[12] = state->t[0] ^ blake2s_iv[4]; ++ v[13] = state->t[1] ^ blake2s_iv[5]; ++ v[14] = state->f[0] ^ blake2s_iv[6]; ++ v[15] = state->f[1] ^ blake2s_iv[7]; ++#define G(r,i,a,b,c,d) \ ++ do { \ ++ a += b + m[blake2s_sigma[r][2 * i + 0]]; \ ++ d = ror32(d ^ a, 16); \ ++ c += d; \ ++ b = ror32(b ^ c, 12); \ ++ a += b + m[blake2s_sigma[r][2 * i + 1]]; \ ++ d = ror32(d ^ a, 8); \ ++ c += d; \ ++ b = ror32(b ^ c, 7); \ ++ } while(0) ++#define ROUND(r) \ ++ do { \ ++ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ ++ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ ++ G(r,2,v[ 2],v[ 6],v[10],v[14]); \ ++ G(r,3,v[ 3],v[ 7],v[11],v[15]); \ ++ G(r,4,v[ 0],v[ 5],v[10],v[15]); \ ++ G(r,5,v[ 1],v[ 6],v[11],v[12]); \ ++ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ ++ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ ++} while(0) ++ ROUND(0); ++ ROUND(1); ++ ROUND(2); ++ ROUND(3); ++ ROUND(4); ++ ROUND(5); ++ ROUND(6); ++ ROUND(7); ++ ROUND(8); ++ ROUND(9); ++ ++ for (i = 0; i < 8; ++i) ++ state->h[i] = state->h[i] ^ v[i] ^ v[i + 8]; ++#undef G ++#undef ROUND ++} ++ ++void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen) ++{ ++ size_t left, fill; ++ while (inlen > 0) { ++ left = state->buflen; ++ fill = 2 * BLAKE2S_BLOCKBYTES - left; ++ ++ if (inlen > fill) { ++ memcpy(state->buf + left, in, fill); // Fill buffer ++ state->buflen += fill; ++ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES); ++ blake2s_compress(state, state->buf); // Compress ++ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES);// Shift buffer left ++ state->buflen -= BLAKE2S_BLOCKBYTES; ++ in += fill; ++ inlen -= fill; ++ } else { // inlen <= fill ++ memcpy(state->buf + left, in, inlen); ++ state->buflen += inlen; // Be lazy, do not compress ++ in += inlen; ++ inlen -= inlen; ++ } ++ } ++} ++ ++void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen) ++{ ++ u8 buffer[BLAKE2S_OUTBYTES] = { 0 }; ++ int i; ++ ++#ifdef DEBUG ++ BUG_ON(!out || !outlen || outlen > BLAKE2S_OUTBYTES); ++#endif ++ ++ if (state->buflen > BLAKE2S_BLOCKBYTES) { ++ blake2s_increment_counter(state, BLAKE2S_BLOCKBYTES); ++ blake2s_compress(state, state->buf); ++ state->buflen -= BLAKE2S_BLOCKBYTES; ++ memcpy(state->buf, state->buf + BLAKE2S_BLOCKBYTES, state->buflen); ++ } ++ ++ blake2s_increment_counter(state, (u32) state->buflen); ++ blake2s_set_lastblock(state); ++ memset(state->buf + state->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - state->buflen); /* Padding */ ++ blake2s_compress(state, state->buf); ++ ++ for (i = 0; i < 8; ++i) /* output full hash to temp buffer */ ++ *(__le32 *)(buffer + sizeof(state->h[i]) * i) = cpu_to_le32(state->h[i]); ++ ++ memcpy(out, buffer, outlen); ++ ++ /* Burn state from stack */ ++ memzero_explicit(buffer, BLAKE2S_OUTBYTES); ++ memzero_explicit(state, sizeof(struct blake2s_state)); ++} ++ ++void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, u64 inlen, const u8 keylen) ++{ ++ struct blake2s_state state; ++ ++#ifdef DEBUG ++ BUG_ON((!in && inlen > 0) || !out || !outlen || outlen > BLAKE2S_OUTBYTES || keylen > BLAKE2S_KEYBYTES); ++#endif ++ ++ if (keylen > 0 && key) ++ blake2s_init_key(&state, outlen, key, keylen); ++ else ++ blake2s_init(&state, outlen); ++ ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, out, outlen); ++} ++ ++void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen) ++{ ++ struct blake2s_state state; ++ u8 o_key[BLAKE2S_BLOCKBYTES] = { 0 }; ++ u8 i_key[BLAKE2S_BLOCKBYTES] = { 0 }; ++ u8 i_hash[BLAKE2S_OUTBYTES]; ++ int i; ++ ++ if (keylen > BLAKE2S_BLOCKBYTES) { ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, key, keylen); ++ blake2s_final(&state, o_key, BLAKE2S_OUTBYTES); ++ memcpy(i_key, o_key, BLAKE2S_OUTBYTES); ++ } else { ++ memcpy(o_key, key, keylen); ++ memcpy(i_key, key, keylen); ++ } ++ ++ for (i = 0; i < BLAKE2S_BLOCKBYTES; ++i) { ++ o_key[i] ^= 0x5c; ++ i_key[i] ^= 0x36; ++ } ++ ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, i_key, BLAKE2S_BLOCKBYTES); ++ blake2s_update(&state, in, inlen); ++ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES); ++ ++ blake2s_init(&state, BLAKE2S_OUTBYTES); ++ blake2s_update(&state, o_key, BLAKE2S_BLOCKBYTES); ++ blake2s_update(&state, i_hash, BLAKE2S_OUTBYTES); ++ blake2s_final(&state, i_hash, BLAKE2S_OUTBYTES); ++ ++ memcpy(out, i_hash, outlen); ++ memzero_explicit(o_key, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(i_key, BLAKE2S_BLOCKBYTES); ++ memzero_explicit(i_hash, BLAKE2S_OUTBYTES); ++} ++ ++#include "../selftest/blake2s.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20poly1305.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,811 @@ ++/* ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ * Copyright 2015 Martin Willi. ++ */ ++ ++#include "chacha20poly1305.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_X86_64 ++#include ++#include ++#ifdef CONFIG_AS_SSSE3 ++asmlinkage void chacha20_asm_block_xor_ssse3(u32 *state, u8 *dst, const u8 *src); ++asmlinkage void chacha20_asm_4block_xor_ssse3(u32 *state, u8 *dst, const u8 *src); ++#endif ++#ifdef CONFIG_AS_AVX2 ++asmlinkage void chacha20_asm_8block_xor_avx2(u32 *state, u8 *dst, const u8 *src); ++#endif ++asmlinkage void poly1305_asm_block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks); ++asmlinkage void poly1305_asm_2block_sse2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u); ++#ifdef CONFIG_AS_AVX2 ++asmlinkage void poly1305_asm_4block_avx2(u32 *h, const u8 *src, const u32 *r, unsigned int blocks, const u32 *u); ++#endif ++static bool chacha20poly1305_use_avx2 __read_mostly = false; ++static bool chacha20poly1305_use_ssse3 __read_mostly = false; ++static bool chacha20poly1305_use_sse2 __read_mostly = false; ++void chacha20poly1305_init(void) ++{ ++ chacha20poly1305_use_sse2 = boot_cpu_has(X86_FEATURE_XMM2); ++ chacha20poly1305_use_ssse3 = boot_cpu_has(X86_FEATURE_SSSE3); ++ chacha20poly1305_use_avx2 = boot_cpu_has(X86_FEATURE_AVX) && boot_cpu_has(X86_FEATURE_AVX2); ++} ++#else ++void chacha20poly1305_init(void) { } ++#endif ++ ++#define CHACHA20_IV_SIZE 16 ++#define CHACHA20_KEY_SIZE 32 ++#define CHACHA20_BLOCK_SIZE 64 ++#define POLY1305_BLOCK_SIZE 16 ++#define POLY1305_KEY_SIZE 32 ++#define POLY1305_MAC_SIZE 16 ++ ++static inline u32 le32_to_cpuvp(const void *p) ++{ ++ return le32_to_cpup(p); ++} ++ ++static inline u64 le64_to_cpuvp(const void *p) ++{ ++ return le64_to_cpup(p); ++} ++ ++static inline u32 rotl32(u32 v, u8 n) ++{ ++ return (v << n) | (v >> (sizeof(v) * 8 - n)); ++} ++ ++static inline u64 mlt(u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++static inline u32 sr(u64 v, u_char n) ++{ ++ return v >> n; ++} ++ ++static inline u32 and(u32 v, u32 mask) ++{ ++ return v & mask; ++} ++ ++struct chacha20_ctx { ++ u32 state[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++} __aligned(32); ++ ++static void chacha20_generic_block(struct chacha20_ctx *ctx, void *stream) ++{ ++ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++ __le32 *out = stream; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(x); i++) ++ x[i] = ctx->state[i]; ++ ++ for (i = 0; i < 20; i += 2) { ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12); ++ ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(x); i++) ++ out[i] = cpu_to_le32(x[i] + ctx->state[i]); ++ ++ ctx->state[12]++; ++} ++ ++static const char constant[16] = "expand 32-byte k"; ++ ++static void hchacha20(u8 derived_key[CHACHA20POLY1305_KEYLEN], const u8 nonce[16], const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u32 x[CHACHA20_BLOCK_SIZE / sizeof(u32)]; ++ __le32 *out = (__force __le32 *)derived_key; ++ int i; ++ ++ x[0] = le32_to_cpuvp(constant + 0); ++ x[1] = le32_to_cpuvp(constant + 4); ++ x[2] = le32_to_cpuvp(constant + 8); ++ x[3] = le32_to_cpuvp(constant + 12); ++ x[4] = le32_to_cpuvp(key + 0); ++ x[5] = le32_to_cpuvp(key + 4); ++ x[6] = le32_to_cpuvp(key + 8); ++ x[7] = le32_to_cpuvp(key + 12); ++ x[8] = le32_to_cpuvp(key + 16); ++ x[9] = le32_to_cpuvp(key + 20); ++ x[10] = le32_to_cpuvp(key + 24); ++ x[11] = le32_to_cpuvp(key + 28); ++ x[12] = le32_to_cpuvp(nonce + 0); ++ x[13] = le32_to_cpuvp(nonce + 4); ++ x[14] = le32_to_cpuvp(nonce + 8); ++ x[15] = le32_to_cpuvp(nonce + 12); ++ ++ for (i = 0; i < 20; i += 2) { ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12); ++ ++ x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8); ++ x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8); ++ x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8); ++ x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8); ++ ++ x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7); ++ x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7); ++ x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7); ++ x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12); ++ ++ x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8); ++ x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8); ++ x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8); ++ x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8); ++ ++ x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7); ++ x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7); ++ x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7); ++ x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7); ++ } ++ ++ out[0] = cpu_to_le32(x[0]); ++ out[1] = cpu_to_le32(x[1]); ++ out[2] = cpu_to_le32(x[2]); ++ out[3] = cpu_to_le32(x[3]); ++ out[4] = cpu_to_le32(x[12]); ++ out[5] = cpu_to_le32(x[13]); ++ out[6] = cpu_to_le32(x[14]); ++ out[7] = cpu_to_le32(x[15]); ++} ++ ++static void chacha20_keysetup(struct chacha20_ctx *ctx, const u8 key[CHACHA20_KEY_SIZE], const u8 nonce[sizeof(u64)]) ++{ ++ ctx->state[0] = le32_to_cpuvp(constant + 0); ++ ctx->state[1] = le32_to_cpuvp(constant + 4); ++ ctx->state[2] = le32_to_cpuvp(constant + 8); ++ ctx->state[3] = le32_to_cpuvp(constant + 12); ++ ctx->state[4] = le32_to_cpuvp(key + 0); ++ ctx->state[5] = le32_to_cpuvp(key + 4); ++ ctx->state[6] = le32_to_cpuvp(key + 8); ++ ctx->state[7] = le32_to_cpuvp(key + 12); ++ ctx->state[8] = le32_to_cpuvp(key + 16); ++ ctx->state[9] = le32_to_cpuvp(key + 20); ++ ctx->state[10] = le32_to_cpuvp(key + 24); ++ ctx->state[11] = le32_to_cpuvp(key + 28); ++ ctx->state[12] = 0; ++ ctx->state[13] = 0; ++ ctx->state[14] = le32_to_cpuvp(nonce + 0); ++ ctx->state[15] = le32_to_cpuvp(nonce + 4); ++} ++ ++static void chacha20_crypt(struct chacha20_ctx *ctx, u8 *dst, const u8 *src, unsigned int bytes, bool have_simd) ++{ ++ u8 buf[CHACHA20_BLOCK_SIZE]; ++ ++ if (!have_simd ++#ifdef CONFIG_X86_64 ++ || !chacha20poly1305_use_ssse3 ++#endif ++ ) ++ goto no_simd; ++ ++#ifdef CONFIG_X86_64 ++#ifdef CONFIG_AS_AVX2 ++ if (chacha20poly1305_use_avx2) { ++ while (bytes >= CHACHA20_BLOCK_SIZE * 8) { ++ chacha20_asm_8block_xor_avx2(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE * 8; ++ src += CHACHA20_BLOCK_SIZE * 8; ++ dst += CHACHA20_BLOCK_SIZE * 8; ++ ctx->state[12] += 8; ++ } ++ } ++#endif ++#ifdef CONFIG_AS_SSSE3 ++ while (bytes >= CHACHA20_BLOCK_SIZE * 4) { ++ chacha20_asm_4block_xor_ssse3(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE * 4; ++ src += CHACHA20_BLOCK_SIZE * 4; ++ dst += CHACHA20_BLOCK_SIZE * 4; ++ ctx->state[12] += 4; ++ } ++ while (bytes >= CHACHA20_BLOCK_SIZE) { ++ chacha20_asm_block_xor_ssse3(ctx->state, dst, src); ++ bytes -= CHACHA20_BLOCK_SIZE; ++ src += CHACHA20_BLOCK_SIZE; ++ dst += CHACHA20_BLOCK_SIZE; ++ ctx->state[12]++; ++ } ++ if (bytes) { ++ memcpy(buf, src, bytes); ++ chacha20_asm_block_xor_ssse3(ctx->state, buf, buf); ++ memcpy(dst, buf, bytes); ++ } ++ return; ++#endif ++#endif ++ ++no_simd: ++ if (dst != src) ++ memcpy(dst, src, bytes); ++ ++ while (bytes >= CHACHA20_BLOCK_SIZE) { ++ chacha20_generic_block(ctx, buf); ++ crypto_xor(dst, buf, CHACHA20_BLOCK_SIZE); ++ bytes -= CHACHA20_BLOCK_SIZE; ++ dst += CHACHA20_BLOCK_SIZE; ++ } ++ if (bytes) { ++ chacha20_generic_block(ctx, buf); ++ crypto_xor(dst, buf, bytes); ++ } ++} ++ ++struct poly1305_ctx { ++ /* key */ ++ u32 r[5]; ++ /* finalize key */ ++ u32 s[4]; ++ /* accumulator */ ++ u32 h[5]; ++ /* partial buffer */ ++ u8 buf[POLY1305_BLOCK_SIZE]; ++ /* bytes used in partial buffer */ ++ unsigned int buflen; ++ /* derived key u set? */ ++ bool uset; ++ /* derived keys r^3, r^4 set? */ ++ bool wset; ++ /* derived Poly1305 key r^2 */ ++ u32 u[5]; ++ /* derived Poly1305 key r^3 */ ++ u32 r3[5]; ++ /* derived Poly1305 key r^4 */ ++ u32 r4[5]; ++}; ++ ++static void poly1305_init(struct poly1305_ctx *ctx, const u8 key[POLY1305_KEY_SIZE]) ++{ ++ memset(ctx, 0, sizeof(struct poly1305_ctx)); ++ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ ++ ctx->r[0] = (le32_to_cpuvp(key + 0) >> 0) & 0x3ffffff; ++ ctx->r[1] = (get_unaligned_le32(key + 3) >> 2) & 0x3ffff03; ++ ctx->r[2] = (get_unaligned_le32(key + 6) >> 4) & 0x3ffc0ff; ++ ctx->r[3] = (get_unaligned_le32(key + 9) >> 6) & 0x3f03fff; ++ ctx->r[4] = (le32_to_cpuvp(key + 12) >> 8) & 0x00fffff; ++ ctx->s[0] = le32_to_cpuvp(key + 16); ++ ctx->s[1] = le32_to_cpuvp(key + 20); ++ ctx->s[2] = le32_to_cpuvp(key + 24); ++ ctx->s[3] = le32_to_cpuvp(key + 28); ++} ++ ++static unsigned int poly1305_generic_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, u32 hibit) ++{ ++ u32 r0, r1, r2, r3, r4; ++ u32 s1, s2, s3, s4; ++ u32 h0, h1, h2, h3, h4; ++ u64 d0, d1, d2, d3, d4; ++ ++ r0 = ctx->r[0]; ++ r1 = ctx->r[1]; ++ r2 = ctx->r[2]; ++ r3 = ctx->r[3]; ++ r4 = ctx->r[4]; ++ ++ s1 = r1 * 5; ++ s2 = r2 * 5; ++ s3 = r3 * 5; ++ s4 = r4 * 5; ++ ++ h0 = ctx->h[0]; ++ h1 = ctx->h[1]; ++ h2 = ctx->h[2]; ++ h3 = ctx->h[3]; ++ h4 = ctx->h[4]; ++ ++ while (likely(srclen >= POLY1305_BLOCK_SIZE)) { ++ /* h += m[i] */ ++ h0 += (le32_to_cpuvp(src + 0) >> 0) & 0x3ffffff; ++ h1 += (get_unaligned_le32(src + 3) >> 2) & 0x3ffffff; ++ h2 += (get_unaligned_le32(src + 6) >> 4) & 0x3ffffff; ++ h3 += (get_unaligned_le32(src + 9) >> 6) & 0x3ffffff; ++ h4 += (le32_to_cpuvp(src + 12) >> 8) | hibit; ++ ++ /* h *= r */ ++ d0 = mlt(h0, r0) + mlt(h1, s4) + mlt(h2, s3) + mlt(h3, s2) + mlt(h4, s1); ++ d1 = mlt(h0, r1) + mlt(h1, r0) + mlt(h2, s4) + mlt(h3, s3) + mlt(h4, s2); ++ d2 = mlt(h0, r2) + mlt(h1, r1) + mlt(h2, r0) + mlt(h3, s4) + mlt(h4, s3); ++ d3 = mlt(h0, r3) + mlt(h1, r2) + mlt(h2, r1) + mlt(h3, r0) + mlt(h4, s4); ++ d4 = mlt(h0, r4) + mlt(h1, r3) + mlt(h2, r2) + mlt(h3, r1) + mlt(h4, r0); ++ ++ /* (partial) h %= p */ ++ d1 += sr(d0, 26); h0 = and(d0, 0x3ffffff); ++ d2 += sr(d1, 26); h1 = and(d1, 0x3ffffff); ++ d3 += sr(d2, 26); h2 = and(d2, 0x3ffffff); ++ d4 += sr(d3, 26); h3 = and(d3, 0x3ffffff); ++ h0 += sr(d4, 26) * 5; h4 = and(d4, 0x3ffffff); ++ h1 += h0 >> 26; h0 = h0 & 0x3ffffff; ++ ++ src += POLY1305_BLOCK_SIZE; ++ srclen -= POLY1305_BLOCK_SIZE; ++ } ++ ++ ctx->h[0] = h0; ++ ctx->h[1] = h1; ++ ctx->h[2] = h2; ++ ctx->h[3] = h3; ++ ctx->h[4] = h4; ++ ++ return srclen; ++} ++ ++#ifdef CONFIG_X86_64 ++static void poly1305_simd_mult(u32 *a, const u32 *b) ++{ ++ u8 m[POLY1305_BLOCK_SIZE]; ++ ++ memset(m, 0, sizeof(m)); ++ /* The poly1305 block function adds a hi-bit to the accumulator which ++ * we don't need for key multiplication; compensate for it. */ ++ a[4] -= 1 << 24; ++ poly1305_asm_block_sse2(a, m, b, 1); ++} ++ ++static unsigned int poly1305_simd_blocks(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen) ++{ ++ unsigned int blocks; ++ ++#ifdef CONFIG_AS_AVX2 ++ if (chacha20poly1305_use_avx2 && srclen >= POLY1305_BLOCK_SIZE * 4) { ++ if (unlikely(!ctx->wset)) { ++ if (!ctx->uset) { ++ memcpy(ctx->u, ctx->r, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->u, ctx->r); ++ ctx->uset = true; ++ } ++ memcpy(ctx->r3, ctx->u, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->r3, ctx->r); ++ memcpy(ctx->r4, ctx->r3, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->r4, ctx->r); ++ ctx->wset = true; ++ } ++ blocks = srclen / (POLY1305_BLOCK_SIZE * 4); ++ poly1305_asm_4block_avx2(ctx->h, src, ctx->r, blocks, ctx->u); ++ src += POLY1305_BLOCK_SIZE * 4 * blocks; ++ srclen -= POLY1305_BLOCK_SIZE * 4 * blocks; ++ } ++#endif ++ if (likely(srclen >= POLY1305_BLOCK_SIZE * 2)) { ++ if (unlikely(!ctx->uset)) { ++ memcpy(ctx->u, ctx->r, sizeof(ctx->u)); ++ poly1305_simd_mult(ctx->u, ctx->r); ++ ctx->uset = true; ++ } ++ blocks = srclen / (POLY1305_BLOCK_SIZE * 2); ++ poly1305_asm_2block_sse2(ctx->h, src, ctx->r, blocks, ctx->u); ++ src += POLY1305_BLOCK_SIZE * 2 * blocks; ++ srclen -= POLY1305_BLOCK_SIZE * 2 * blocks; ++ } ++ if (srclen >= POLY1305_BLOCK_SIZE) { ++ poly1305_asm_block_sse2(ctx->h, src, ctx->r, 1); ++ srclen -= POLY1305_BLOCK_SIZE; ++ } ++ return srclen; ++} ++#endif ++ ++static void poly1305_update(struct poly1305_ctx *ctx, const u8 *src, unsigned int srclen, bool have_simd) ++{ ++ unsigned int bytes; ++ ++ if (unlikely(ctx->buflen)) { ++ bytes = min(srclen, POLY1305_BLOCK_SIZE - ctx->buflen); ++ memcpy(ctx->buf + ctx->buflen, src, bytes); ++ src += bytes; ++ srclen -= bytes; ++ ctx->buflen += bytes; ++ ++ if (ctx->buflen == POLY1305_BLOCK_SIZE) { ++#ifdef CONFIG_X86_64 ++ ++ if (have_simd && chacha20poly1305_use_sse2) ++ poly1305_simd_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE); ++ else ++#endif ++ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 1 << 24); ++ ctx->buflen = 0; ++ } ++ } ++ ++ if (likely(srclen >= POLY1305_BLOCK_SIZE)) { ++#ifdef CONFIG_X86_64 ++ ++ if (have_simd && chacha20poly1305_use_sse2) ++ bytes = poly1305_simd_blocks(ctx, src, srclen); ++ else ++#endif ++ bytes = poly1305_generic_blocks(ctx, src, srclen, 1 << 24); ++ src += srclen - bytes; ++ srclen = bytes; ++ } ++ ++ if (unlikely(srclen)) { ++ ctx->buflen = srclen; ++ memcpy(ctx->buf, src, srclen); ++ } ++} ++ ++static void poly1305_finish(struct poly1305_ctx *ctx, u8 *dst) ++{ ++ __le32 *mac = (__le32 *)dst; ++ u32 h0, h1, h2, h3, h4; ++ u32 g0, g1, g2, g3, g4; ++ u32 mask; ++ u64 f = 0; ++ ++ if (unlikely(ctx->buflen)) { ++ ctx->buf[ctx->buflen++] = 1; ++ memset(ctx->buf + ctx->buflen, 0, POLY1305_BLOCK_SIZE - ctx->buflen); ++ poly1305_generic_blocks(ctx, ctx->buf, POLY1305_BLOCK_SIZE, 0); ++ } ++ ++ /* fully carry h */ ++ h0 = ctx->h[0]; ++ h1 = ctx->h[1]; ++ h2 = ctx->h[2]; ++ h3 = ctx->h[3]; ++ h4 = ctx->h[4]; ++ ++ h2 += (h1 >> 26); h1 = h1 & 0x3ffffff; ++ h3 += (h2 >> 26); h2 = h2 & 0x3ffffff; ++ h4 += (h3 >> 26); h3 = h3 & 0x3ffffff; ++ h0 += (h4 >> 26) * 5; h4 = h4 & 0x3ffffff; ++ h1 += (h0 >> 26); h0 = h0 & 0x3ffffff; ++ ++ /* compute h + -p */ ++ g0 = h0 + 5; ++ g1 = h1 + (g0 >> 26); g0 &= 0x3ffffff; ++ g2 = h2 + (g1 >> 26); g1 &= 0x3ffffff; ++ g3 = h3 + (g2 >> 26); g2 &= 0x3ffffff; ++ g4 = h4 + (g3 >> 26) - (1 << 26); g3 &= 0x3ffffff; ++ ++ /* select h if h < p, or h + -p if h >= p */ ++ mask = (g4 >> ((sizeof(u32) * 8) - 1)) - 1; ++ g0 &= mask; ++ g1 &= mask; ++ g2 &= mask; ++ g3 &= mask; ++ g4 &= mask; ++ mask = ~mask; ++ h0 = (h0 & mask) | g0; ++ h1 = (h1 & mask) | g1; ++ h2 = (h2 & mask) | g2; ++ h3 = (h3 & mask) | g3; ++ h4 = (h4 & mask) | g4; ++ ++ /* h = h % (2^128) */ ++ h0 = (h0 >> 0) | (h1 << 26); ++ h1 = (h1 >> 6) | (h2 << 20); ++ h2 = (h2 >> 12) | (h3 << 14); ++ h3 = (h3 >> 18) | (h4 << 8); ++ ++ /* mac = (h + s) % (2^128) */ ++ f = (f >> 32) + h0 + ctx->s[0]; mac[0] = cpu_to_le32(f); ++ f = (f >> 32) + h1 + ctx->s[1]; mac[1] = cpu_to_le32(f); ++ f = (f >> 32) + h2 + ctx->s[2]; mac[2] = cpu_to_le32(f); ++ f = (f >> 32) + h3 + ctx->s[3]; mac[3] = cpu_to_le32(f); ++} ++ ++static const u8 pad0[16] = { 0 }; ++ ++static struct crypto_alg chacha20_alg = { ++ .cra_blocksize = 1, ++ .cra_alignmask = sizeof(u32) - 1 ++}; ++static struct crypto_blkcipher chacha20_cipher = { ++ .base = { ++ .__crt_alg = &chacha20_alg ++ } ++}; ++static struct blkcipher_desc chacha20_desc = { ++ .tfm = &chacha20_cipher ++}; ++ ++bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ chacha20_crypt(&chacha20_state, dst, src, src_len, have_simd); ++ ++ poly1305_update(&poly1305_state, dst, src_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, dst + src_len); ++ ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ ++ chacha20poly1305_deinit_simd(have_simd); ++ ++ return true; ++} ++ ++bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN], ++ bool have_simd) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ struct blkcipher_walk walk; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 mac[POLY1305_MAC_SIZE]; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ if (likely(src_len)) { ++ blkcipher_walk_init(&walk, dst, src, src_len); ++ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE); ++ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) { ++ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd); ++ poly1305_update(&poly1305_state, walk.dst.virt.addr, chunk_len, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE); ++ } ++ if (walk.nbytes) { ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd); ++ poly1305_update(&poly1305_state, walk.dst.virt.addr, walk.nbytes, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, 0); ++ } ++ } ++ ++ poly1305_update(&poly1305_state, pad0, (0x10 - src_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(src_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, mac); ++ scatterwalk_map_and_copy(mac, dst, src_len, sizeof(mac), 1); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ memzero_explicit(mac, sizeof(mac)); ++ return true; ++} ++ ++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ int ret; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 mac[POLY1305_MAC_SIZE]; ++ size_t dst_len; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd; ++ ++ if (unlikely(src_len < POLY1305_MAC_SIZE)) ++ return false; ++ ++ have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ dst_len = src_len - POLY1305_MAC_SIZE; ++ poly1305_update(&poly1305_state, src, dst_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(dst_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, mac); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ ++ ret = crypto_memneq(mac, src + dst_len, POLY1305_MAC_SIZE); ++ memzero_explicit(mac, POLY1305_MAC_SIZE); ++ if (likely(!ret)) ++ chacha20_crypt(&chacha20_state, dst, src, dst_len, have_simd); ++ ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ ++ chacha20poly1305_deinit_simd(have_simd); ++ return !ret; ++} ++ ++bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ struct poly1305_ctx poly1305_state; ++ struct chacha20_ctx chacha20_state; ++ struct blkcipher_walk walk; ++ int ret; ++ u8 block0[CHACHA20_BLOCK_SIZE] = { 0 }; ++ u8 read_mac[POLY1305_MAC_SIZE], computed_mac[POLY1305_MAC_SIZE]; ++ size_t dst_len; ++ __le64 len; ++ __le64 le_nonce = cpu_to_le64(nonce); ++ bool have_simd; ++ ++ if (unlikely(src_len < POLY1305_MAC_SIZE)) ++ return false; ++ ++ have_simd = chacha20poly1305_init_simd(); ++ ++ chacha20_keysetup(&chacha20_state, key, (u8 *)&le_nonce); ++ ++ chacha20_crypt(&chacha20_state, block0, block0, sizeof(block0), have_simd); ++ poly1305_init(&poly1305_state, block0); ++ memzero_explicit(block0, sizeof(block0)); ++ ++ poly1305_update(&poly1305_state, ad, ad_len, have_simd); ++ poly1305_update(&poly1305_state, pad0, (0x10 - ad_len) & 0xf, have_simd); ++ ++ dst_len = src_len - POLY1305_MAC_SIZE; ++ if (likely(dst_len)) { ++ blkcipher_walk_init(&walk, dst, src, dst_len); ++ blkcipher_walk_virt_block(&chacha20_desc, &walk, CHACHA20_BLOCK_SIZE); ++ while (walk.nbytes >= CHACHA20_BLOCK_SIZE) { ++ size_t chunk_len = rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE); ++ poly1305_update(&poly1305_state, walk.src.virt.addr, chunk_len, have_simd); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, chunk_len, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, walk.nbytes % CHACHA20_BLOCK_SIZE); ++ } ++ if (walk.nbytes) { ++ poly1305_update(&poly1305_state, walk.src.virt.addr, walk.nbytes, have_simd); ++ chacha20_crypt(&chacha20_state, walk.dst.virt.addr, walk.src.virt.addr, walk.nbytes, have_simd); ++ blkcipher_walk_done(&chacha20_desc, &walk, 0); ++ } ++ } ++ ++ poly1305_update(&poly1305_state, pad0, (0x10 - dst_len) & 0xf, have_simd); ++ ++ len = cpu_to_le64(ad_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ len = cpu_to_le64(dst_len); ++ poly1305_update(&poly1305_state, (u8 *)&len, sizeof(len), have_simd); ++ ++ poly1305_finish(&poly1305_state, computed_mac); ++ memzero_explicit(&poly1305_state, sizeof(poly1305_state)); ++ ++ scatterwalk_map_and_copy(read_mac, src, dst_len, POLY1305_MAC_SIZE, 0); ++ ret = crypto_memneq(read_mac, computed_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(read_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(computed_mac, POLY1305_MAC_SIZE); ++ memzero_explicit(&chacha20_state, sizeof(chacha20_state)); ++ chacha20poly1305_deinit_simd(have_simd); ++ return !ret; ++} ++ ++ ++bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u8 derived_key[CHACHA20POLY1305_KEYLEN]; ++ bool ret; ++ hchacha20(derived_key, nonce, key); ++ ret = chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key); ++ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN); ++ return ret; ++} ++ ++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]) ++{ ++ u8 derived_key[CHACHA20POLY1305_KEYLEN]; ++ bool ret; ++ hchacha20(derived_key, nonce, key); ++ ret = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, le64_to_cpuvp(nonce + 16), derived_key); ++ memzero_explicit(derived_key, CHACHA20POLY1305_KEYLEN); ++ return ret; ++} ++ ++#include "../selftest/chacha20poly1305.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/curve25519.c 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,1240 @@ ++/* Original author: Adam Langley ++ * ++ * Copyright 2008 Google Inc. All Rights Reserved. ++ * Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. ++ */ ++ ++#include "curve25519.h" ++ ++#include ++#include ++#include ++ ++static __always_inline void normalize_secret(u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ secret[0] &= 248; ++ secret[31] &= 127; ++ secret[31] |= 64; ++} ++ ++#ifdef __SIZEOF_INT128__ ++typedef u64 limb; ++typedef limb felem[5]; ++typedef __uint128_t uint128_t; ++ ++/* Sum two numbers: output += in */ ++static __always_inline void fsum(limb *output, const limb *in) ++{ ++ output[0] += in[0]; ++ output[1] += in[1]; ++ output[2] += in[2]; ++ output[3] += in[3]; ++ output[4] += in[4]; ++} ++ ++/* Find the difference of two numbers: output = in - output ++ * (note the order of the arguments!) ++ * ++ * Assumes that out[i] < 2**52 ++ * On return, out[i] < 2**55 ++ */ ++static __always_inline void fdifference_backwards(felem out, const felem in) ++{ ++ /* 152 is 19 << 3 */ ++ static const limb two54m152 = (((limb)1) << 54) - 152; ++ static const limb two54m8 = (((limb)1) << 54) - 8; ++ ++ out[0] = in[0] + two54m152 - out[0]; ++ out[1] = in[1] + two54m8 - out[1]; ++ out[2] = in[2] + two54m8 - out[2]; ++ out[3] = in[3] + two54m8 - out[3]; ++ out[4] = in[4] + two54m8 - out[4]; ++} ++ ++/* Multiply a number by a scalar: output = in * scalar */ ++static __always_inline void fscalar_product(felem output, const felem in, const limb scalar) ++{ ++ uint128_t a; ++ ++ a = ((uint128_t) in[0]) * scalar; ++ output[0] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[1]) * scalar + ((limb) (a >> 51)); ++ output[1] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[2]) * scalar + ((limb) (a >> 51)); ++ output[2] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[3]) * scalar + ((limb) (a >> 51)); ++ output[3] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ a = ((uint128_t) in[4]) * scalar + ((limb) (a >> 51)); ++ output[4] = ((limb)a) & 0x7ffffffffffffUL; ++ ++ output[0] += (a >> 51) * 19; ++} ++ ++/* Multiply two numbers: output = in2 * in ++ * ++ * output must be distinct to both inputs. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * Assumes that in[i] < 2**55 and likewise for in2. ++ * On return, output[i] < 2**52 ++ */ ++static __always_inline void fmul(felem output, const felem in2, const felem in) ++{ ++ uint128_t t[5]; ++ limb r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c; ++ ++ r0 = in[0]; ++ r1 = in[1]; ++ r2 = in[2]; ++ r3 = in[3]; ++ r4 = in[4]; ++ ++ s0 = in2[0]; ++ s1 = in2[1]; ++ s2 = in2[2]; ++ s3 = in2[3]; ++ s4 = in2[4]; ++ ++ t[0] = ((uint128_t) r0) * s0; ++ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0; ++ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1; ++ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1; ++ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2; ++ ++ r4 *= 19; ++ r1 *= 19; ++ r2 *= 19; ++ r3 *= 19; ++ ++ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2; ++ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3; ++ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4; ++ t[3] += ((uint128_t) r4) * s4; ++ ++ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51); ++ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51); ++ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51); ++ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51); ++ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51); ++ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL; ++ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL; ++ r2 += c; ++ ++ output[0] = r0; ++ output[1] = r1; ++ output[2] = r2; ++ output[3] = r3; ++ output[4] = r4; ++} ++ ++static __always_inline void fsquare_times(felem output, const felem in, limb count) ++{ ++ uint128_t t[5]; ++ limb r0,r1,r2,r3,r4,c; ++ limb d0,d1,d2,d4,d419; ++ ++ r0 = in[0]; ++ r1 = in[1]; ++ r2 = in[2]; ++ r3 = in[3]; ++ r4 = in[4]; ++ ++ do { ++ d0 = r0 * 2; ++ d1 = r1 * 2; ++ d2 = r2 * 2 * 19; ++ d419 = r4 * 19; ++ d4 = d419 * 2; ++ ++ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 )); ++ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19)); ++ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 )); ++ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 )); ++ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 )); ++ ++ r0 = (limb)t[0] & 0x7ffffffffffffUL; c = (limb)(t[0] >> 51); ++ t[1] += c; r1 = (limb)t[1] & 0x7ffffffffffffUL; c = (limb)(t[1] >> 51); ++ t[2] += c; r2 = (limb)t[2] & 0x7ffffffffffffUL; c = (limb)(t[2] >> 51); ++ t[3] += c; r3 = (limb)t[3] & 0x7ffffffffffffUL; c = (limb)(t[3] >> 51); ++ t[4] += c; r4 = (limb)t[4] & 0x7ffffffffffffUL; c = (limb)(t[4] >> 51); ++ r0 += c * 19; c = r0 >> 51; r0 = r0 & 0x7ffffffffffffUL; ++ r1 += c; c = r1 >> 51; r1 = r1 & 0x7ffffffffffffUL; ++ r2 += c; ++ } while(--count); ++ ++ output[0] = r0; ++ output[1] = r1; ++ output[2] = r2; ++ output[3] = r3; ++ output[4] = r4; ++} ++ ++/* Load a little-endian 64-bit number */ ++static inline limb load_limb(const u8 *in) ++{ ++ return le64_to_cpu(*(u64 *)in); ++} ++ ++static inline void store_limb(u8 *out, limb in) ++{ ++ *(u64 *)out = cpu_to_le64(in); ++} ++ ++/* Take a little-endian, 32-byte number and expand it into polynomial form */ ++static inline void fexpand(limb *output, const u8 *in) ++{ ++ output[0] = load_limb(in) & 0x7ffffffffffffUL; ++ output[1] = (load_limb(in + 6) >> 3) & 0x7ffffffffffffUL; ++ output[2] = (load_limb(in + 12) >> 6) & 0x7ffffffffffffUL; ++ output[3] = (load_limb(in + 19) >> 1) & 0x7ffffffffffffUL; ++ output[4] = (load_limb(in + 24) >> 12) & 0x7ffffffffffffUL; ++} ++ ++/* Take a fully reduced polynomial form number and contract it into a ++ * little-endian, 32-byte array ++ */ ++static void fcontract(u8 *output, const felem input) ++{ ++ uint128_t t[5]; ++ ++ t[0] = input[0]; ++ t[1] = input[1]; ++ t[2] = input[2]; ++ t[3] = input[3]; ++ t[4] = input[4]; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ /* now t is between 0 and 2^255-1, properly carried. */ ++ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ ++ ++ t[0] += 19; ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[0] += 19 * (t[4] >> 51); t[4] &= 0x7ffffffffffffUL; ++ ++ /* now between 19 and 2^255-1 in both cases, and offset by 19. */ ++ ++ t[0] += 0x8000000000000UL - 19; ++ t[1] += 0x8000000000000UL - 1; ++ t[2] += 0x8000000000000UL - 1; ++ t[3] += 0x8000000000000UL - 1; ++ t[4] += 0x8000000000000UL - 1; ++ ++ /* now between 2^255 and 2^256-20, and offset by 2^255. */ ++ ++ t[1] += t[0] >> 51; t[0] &= 0x7ffffffffffffUL; ++ t[2] += t[1] >> 51; t[1] &= 0x7ffffffffffffUL; ++ t[3] += t[2] >> 51; t[2] &= 0x7ffffffffffffUL; ++ t[4] += t[3] >> 51; t[3] &= 0x7ffffffffffffUL; ++ t[4] &= 0x7ffffffffffffUL; ++ ++ store_limb(output, t[0] | (t[1] << 51)); ++ store_limb(output+8, (t[1] >> 13) | (t[2] << 38)); ++ store_limb(output+16, (t[2] >> 26) | (t[3] << 25)); ++ store_limb(output+24, (t[3] >> 39) | (t[4] << 12)); ++} ++ ++/* Input: Q, Q', Q-Q' ++ * Output: 2Q, Q+Q' ++ * ++ * x2 z3: long form ++ * x3 z3: long form ++ * x z: short form, destroyed ++ * xprime zprime: short form, destroyed ++ * qmqp: short form, preserved ++ */ ++static void fmonty(limb *x2, limb *z2, /* output 2Q */ ++ limb *x3, limb *z3, /* output Q + Q' */ ++ limb *x, limb *z, /* input Q */ ++ limb *xprime, limb *zprime, /* input Q' */ ++ const limb *qmqp /* input Q - Q' */) ++{ ++ limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5], zzprime[5], zzzprime[5]; ++ ++ memcpy(origx, x, 5 * sizeof(limb)); ++ fsum(x, z); ++ fdifference_backwards(z, origx); // does x - z ++ ++ memcpy(origxprime, xprime, sizeof(limb) * 5); ++ fsum(xprime, zprime); ++ fdifference_backwards(zprime, origxprime); ++ fmul(xxprime, xprime, z); ++ fmul(zzprime, x, zprime); ++ memcpy(origxprime, xxprime, sizeof(limb) * 5); ++ fsum(xxprime, zzprime); ++ fdifference_backwards(zzprime, origxprime); ++ fsquare_times(x3, xxprime, 1); ++ fsquare_times(zzzprime, zzprime, 1); ++ fmul(z3, zzzprime, qmqp); ++ ++ fsquare_times(xx, x, 1); ++ fsquare_times(zz, z, 1); ++ fmul(x2, xx, zz); ++ fdifference_backwards(zz, xx); // does zz = xx - zz ++ fscalar_product(zzz, zz, 121665); ++ fsum(zzz, xx); ++ fmul(z2, zz, zzz); ++} ++ ++/* Maybe swap the contents of two limb arrays (@a and @b), each @len elements ++ * long. Perform the swap iff @swap is non-zero. ++ * ++ * This function performs the swap without leaking any side-channel ++ * information. ++ */ ++static void swap_conditional(limb a[5], limb b[5], limb iswap) ++{ ++ unsigned i; ++ const limb swap = -iswap; ++ ++ for (i = 0; i < 5; ++i) { ++ const limb x = swap & (a[i] ^ b[i]); ++ a[i] ^= x; ++ b[i] ^= x; ++ } ++} ++ ++/* Calculates nQ where Q is the x-coordinate of a point on the curve ++ * ++ * resultx/resultz: the x coordinate of the resulting curve point (short form) ++ * n: a little endian, 32-byte number ++ * q: a point of the curve (short form) ++ */ ++static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) ++{ ++ limb a[5] = {0}, b[5] = {1}, c[5] = {1}, d[5] = {0}; ++ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; ++ limb e[5] = {0}, f[5] = {1}, g[5] = {0}, h[5] = {1}; ++ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; ++ ++ unsigned i, j; ++ ++ memcpy(nqpqx, q, sizeof(limb) * 5); ++ ++ for (i = 0; i < 32; ++i) { ++ u8 byte = n[31 - i]; ++ for (j = 0; j < 8; ++j) { ++ const limb bit = byte >> 7; ++ ++ swap_conditional(nqx, nqpqx, bit); ++ swap_conditional(nqz, nqpqz, bit); ++ fmonty(nqx2, nqz2, ++ nqpqx2, nqpqz2, ++ nqx, nqz, ++ nqpqx, nqpqz, ++ q); ++ swap_conditional(nqx2, nqpqx2, bit); ++ swap_conditional(nqz2, nqpqz2, bit); ++ ++ t = nqx; ++ nqx = nqx2; ++ nqx2 = t; ++ t = nqz; ++ nqz = nqz2; ++ nqz2 = t; ++ t = nqpqx; ++ nqpqx = nqpqx2; ++ nqpqx2 = t; ++ t = nqpqz; ++ nqpqz = nqpqz2; ++ nqpqz2 = t; ++ ++ byte <<= 1; ++ } ++ } ++ ++ memcpy(resultx, nqx, sizeof(limb) * 5); ++ memcpy(resultz, nqz, sizeof(limb) * 5); ++} ++ ++static void crecip(felem out, const felem z) ++{ ++ felem a,t0,b,c; ++ ++ /* 2 */ fsquare_times(a, z, 1); // a = 2 ++ /* 8 */ fsquare_times(t0, a, 2); ++ /* 9 */ fmul(b, t0, z); // b = 9 ++ /* 11 */ fmul(a, b, a); // a = 11 ++ /* 22 */ fsquare_times(t0, a, 1); ++ /* 2^5 - 2^0 = 31 */ fmul(b, t0, b); ++ /* 2^10 - 2^5 */ fsquare_times(t0, b, 5); ++ /* 2^10 - 2^0 */ fmul(b, t0, b); ++ /* 2^20 - 2^10 */ fsquare_times(t0, b, 10); ++ /* 2^20 - 2^0 */ fmul(c, t0, b); ++ /* 2^40 - 2^20 */ fsquare_times(t0, c, 20); ++ /* 2^40 - 2^0 */ fmul(t0, t0, c); ++ /* 2^50 - 2^10 */ fsquare_times(t0, t0, 10); ++ /* 2^50 - 2^0 */ fmul(b, t0, b); ++ /* 2^100 - 2^50 */ fsquare_times(t0, b, 50); ++ /* 2^100 - 2^0 */ fmul(c, t0, b); ++ /* 2^200 - 2^100 */ fsquare_times(t0, c, 100); ++ /* 2^200 - 2^0 */ fmul(t0, t0, c); ++ /* 2^250 - 2^50 */ fsquare_times(t0, t0, 50); ++ /* 2^250 - 2^0 */ fmul(t0, t0, b); ++ /* 2^255 - 2^5 */ fsquare_times(t0, t0, 5); ++ /* 2^255 - 21 */ fmul(out, t0, a); ++} ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]) ++{ ++ limb bp[5], x[5], z[5], zmone[5]; ++ u8 e[32]; ++ ++ memcpy(e, secret, 32); ++ normalize_secret(e); ++ ++ fexpand(bp, basepoint); ++ cmult(x, z, e, bp); ++ crecip(zmone, z); ++ fmul(z, x, zmone); ++ fcontract(mypublic, z); ++ ++ memzero_explicit(e, sizeof(e)); ++ memzero_explicit(bp, sizeof(bp)); ++ memzero_explicit(x, sizeof(x)); ++ memzero_explicit(z, sizeof(z)); ++ memzero_explicit(zmone, sizeof(zmone)); ++} ++ ++#else ++typedef s64 limb; ++ ++/* Field element representation: ++ * ++ * Field elements are written as an array of signed, 64-bit limbs, least ++ * significant first. The value of the field element is: ++ * x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ... ++ * ++ * i.e. the limbs are 26, 25, 26, 25, ... bits wide. */ ++ ++/* Sum two numbers: output += in */ ++static void fsum(limb *output, const limb *in) ++{ ++ unsigned i; ++ for (i = 0; i < 10; i += 2) { ++ output[0 + i] = output[0 + i] + in[0 + i]; ++ output[1 + i] = output[1 + i] + in[1 + i]; ++ } ++} ++ ++/* Find the difference of two numbers: output = in - output ++ * (note the order of the arguments!). */ ++static void fdifference(limb *output, const limb *in) ++{ ++ unsigned i; ++ for (i = 0; i < 10; ++i) ++ output[i] = in[i] - output[i]; ++} ++ ++/* Multiply a number by a scalar: output = in * scalar */ ++static void fscalar_product(limb *output, const limb *in, const limb scalar) ++{ ++ unsigned i; ++ for (i = 0; i < 10; ++i) ++ output[i] = in[i] * scalar; ++} ++ ++/* Multiply two numbers: output = in2 * in ++ * ++ * output must be distinct to both inputs. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * output[x] <= 14 * the largest product of the input limbs. */ ++static void fproduct(limb *output, const limb *in2, const limb *in) ++{ ++ output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); ++ output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[0]); ++ output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[0]); ++ output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[0]); ++ output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + ++ 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[0])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[0]); ++ output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[0]); ++ output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[2])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[0]); ++ output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[0]); ++ output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + ++ 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[2])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[0]); ++ output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[2]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[1]) + ++ ((limb) ((s32) in2[0])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[0]); ++ output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[1])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[1])) + ++ ((limb) ((s32) in2[4])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[2]); ++ output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[4]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[3]) + ++ ((limb) ((s32) in2[2])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[2]); ++ output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + ++ 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[3])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[3])) + ++ ((limb) ((s32) in2[4])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[4]); ++ output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[7])) * ((s32) in[6]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[5]) + ++ ((limb) ((s32) in2[4])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[4]); ++ output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[5])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[5])) + ++ ((limb) ((s32) in2[6])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[6]); ++ output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + ++ ((limb) ((s32) in2[8])) * ((s32) in[7]) + ++ ((limb) ((s32) in2[6])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[6]); ++ output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[7])); ++ output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + ++ ((limb) ((s32) in2[9])) * ((s32) in[8]); ++ output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); ++} ++ ++/* Reduce a long form to a short form by taking the input mod 2^255 - 19. ++ * ++ * On entry: |output[i]| < 14*2^54 ++ * On exit: |output[0..8]| < 280*2^54 */ ++static void freduce_degree(limb *output) ++{ ++ /* Each of these shifts and adds ends up multiplying the value by 19. ++ * ++ * For output[0..8], the absolute entry value is < 14*2^54 and we add, at ++ * most, 19*14*2^54 thus, on exit, |output[0..8]| < 280*2^54. */ ++ output[8] += output[18] << 4; ++ output[8] += output[18] << 1; ++ output[8] += output[18]; ++ output[7] += output[17] << 4; ++ output[7] += output[17] << 1; ++ output[7] += output[17]; ++ output[6] += output[16] << 4; ++ output[6] += output[16] << 1; ++ output[6] += output[16]; ++ output[5] += output[15] << 4; ++ output[5] += output[15] << 1; ++ output[5] += output[15]; ++ output[4] += output[14] << 4; ++ output[4] += output[14] << 1; ++ output[4] += output[14]; ++ output[3] += output[13] << 4; ++ output[3] += output[13] << 1; ++ output[3] += output[13]; ++ output[2] += output[12] << 4; ++ output[2] += output[12] << 1; ++ output[2] += output[12]; ++ output[1] += output[11] << 4; ++ output[1] += output[11] << 1; ++ output[1] += output[11]; ++ output[0] += output[10] << 4; ++ output[0] += output[10] << 1; ++ output[0] += output[10]; ++} ++ ++#if (-1 & 3) != 3 ++#error "This code only works on a two's complement system" ++#endif ++ ++/* return v / 2^26, using only shifts and adds. ++ * ++ * On entry: v can take any value. */ ++static inline limb div_by_2_26(const limb v) ++{ ++ /* High word of v; no shift needed. */ ++ const u32 highword = (u32) (((u64) v) >> 32); ++ /* Set to all 1s if v was negative; else set to 0s. */ ++ const s32 sign = ((s32) highword) >> 31; ++ /* Set to 0x3ffffff if v was negative; else set to 0. */ ++ const s32 roundoff = ((u32) sign) >> 6; ++ /* Should return v / (1<<26) */ ++ return (v + roundoff) >> 26; ++} ++ ++/* return v / (2^25), using only shifts and adds. ++ * ++ * On entry: v can take any value. */ ++static inline limb div_by_2_25(const limb v) ++{ ++ /* High word of v; no shift needed*/ ++ const u32 highword = (u32) (((u64) v) >> 32); ++ /* Set to all 1s if v was negative; else set to 0s. */ ++ const s32 sign = ((s32) highword) >> 31; ++ /* Set to 0x1ffffff if v was negative; else set to 0. */ ++ const s32 roundoff = ((u32) sign) >> 7; ++ /* Should return v / (1<<25) */ ++ return (v + roundoff) >> 25; ++} ++ ++/* Reduce all coefficients of the short form input so that |x| < 2^26. ++ * ++ * On entry: |output[i]| < 280*2^54 */ ++static void freduce_coefficients(limb *output) ++{ ++ unsigned i; ++ ++ output[10] = 0; ++ ++ for (i = 0; i < 10; i += 2) { ++ limb over = div_by_2_26(output[i]); ++ /* The entry condition (that |output[i]| < 280*2^54) means that over is, at ++ * most, 280*2^28 in the first iteration of this loop. This is added to the ++ * next limb and we can approximate the resulting bound of that limb by ++ * 281*2^54. */ ++ output[i] -= over << 26; ++ output[i+1] += over; ++ ++ /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < ++ * 281*2^29. When this is added to the next limb, the resulting bound can ++ * be approximated as 281*2^54. ++ * ++ * For subsequent iterations of the loop, 281*2^54 remains a conservative ++ * bound and no overflow occurs. */ ++ over = div_by_2_25(output[i+1]); ++ output[i+1] -= over << 25; ++ output[i+2] += over; ++ } ++ /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ ++ output[0] += output[10] << 4; ++ output[0] += output[10] << 1; ++ output[0] += output[10]; ++ ++ output[10] = 0; ++ ++ /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 ++ * So |over| will be no more than 2^16. */ ++ { ++ limb over = div_by_2_26(output[0]); ++ output[0] -= over << 26; ++ output[1] += over; ++ } ++ ++ /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The ++ * bound on |output[1]| is sufficient to meet our needs. */ ++} ++ ++/* A helpful wrapper around fproduct: output = in * in2. ++ * ++ * On entry: |in[i]| < 2^27 and |in2[i]| < 2^27. ++ * ++ * output must be distinct to both inputs. The output is reduced degree ++ * (indeed, one need only provide storage for 10 limbs) and |output[i]| < 2^26. */ ++static void fmul(limb *output, const limb *in, const limb *in2) ++{ ++ limb t[19]; ++ fproduct(t, in, in2); ++ /* |t[i]| < 14*2^54 */ ++ freduce_degree(t); ++ freduce_coefficients(t); ++ /* |t[i]| < 2^26 */ ++ memcpy(output, t, sizeof(limb) * 10); ++} ++ ++/* Square a number: output = in**2 ++ * ++ * output must be distinct from the input. The inputs are reduced coefficient ++ * form, the output is not. ++ * ++ * output[x] <= 14 * the largest product of the input limbs. */ ++static void fsquare_inner(limb *output, const limb *in) ++{ ++ output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); ++ output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); ++ output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + ++ ((limb) ((s32) in[0])) * ((s32) in[2])); ++ output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + ++ ((limb) ((s32) in[0])) * ((s32) in[3])); ++ output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + ++ 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + ++ 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); ++ output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + ++ ((limb) ((s32) in[1])) * ((s32) in[4]) + ++ ((limb) ((s32) in[0])) * ((s32) in[5])); ++ output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + ++ ((limb) ((s32) in[2])) * ((s32) in[4]) + ++ ((limb) ((s32) in[0])) * ((s32) in[6]) + ++ 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); ++ output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + ++ ((limb) ((s32) in[2])) * ((s32) in[5]) + ++ ((limb) ((s32) in[1])) * ((s32) in[6]) + ++ ((limb) ((s32) in[0])) * ((s32) in[7])); ++ output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + ++ 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + ++ ((limb) ((s32) in[0])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[5]))); ++ output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + ++ ((limb) ((s32) in[3])) * ((s32) in[6]) + ++ ((limb) ((s32) in[2])) * ((s32) in[7]) + ++ ((limb) ((s32) in[1])) * ((s32) in[8]) + ++ ((limb) ((s32) in[0])) * ((s32) in[9])); ++ output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + ++ ((limb) ((s32) in[4])) * ((s32) in[6]) + ++ ((limb) ((s32) in[2])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + ++ ((limb) ((s32) in[1])) * ((s32) in[9]))); ++ output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + ++ ((limb) ((s32) in[4])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[8]) + ++ ((limb) ((s32) in[2])) * ((s32) in[9])); ++ output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + ++ 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + ++ 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + ++ ((limb) ((s32) in[3])) * ((s32) in[9]))); ++ output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + ++ ((limb) ((s32) in[5])) * ((s32) in[8]) + ++ ((limb) ((s32) in[4])) * ((s32) in[9])); ++ output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + ++ ((limb) ((s32) in[6])) * ((s32) in[8]) + ++ 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); ++ output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + ++ ((limb) ((s32) in[6])) * ((s32) in[9])); ++ output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + ++ 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); ++ output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); ++ output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); ++} ++ ++/* fsquare sets output = in^2. ++ * ++ * On entry: The |in| argument is in reduced coefficients form and |in[i]| < ++ * 2^27. ++ * ++ * On exit: The |output| argument is in reduced coefficients form (indeed, one ++ * need only provide storage for 10 limbs) and |out[i]| < 2^26. */ ++static void fsquare(limb *output, const limb *in) ++{ ++ limb t[19]; ++ fsquare_inner(t, in); ++ /* |t[i]| < 14*2^54 because the largest product of two limbs will be < ++ * 2^(27+27) and fsquare_inner adds together, at most, 14 of those ++ * products. */ ++ freduce_degree(t); ++ freduce_coefficients(t); ++ /* |t[i]| < 2^26 */ ++ memcpy(output, t, sizeof(limb) * 10); ++} ++ ++/* Take a little-endian, 32-byte number and expand it into polynomial form */ ++static inline void fexpand(limb *output, const u8 *input) ++{ ++#define F(n,start,shift,mask) \ ++ output[n] = ((((limb) input[start + 0]) | \ ++ ((limb) input[start + 1]) << 8 | \ ++ ((limb) input[start + 2]) << 16 | \ ++ ((limb) input[start + 3]) << 24) >> shift) & mask; ++ F(0, 0, 0, 0x3ffffff); ++ F(1, 3, 2, 0x1ffffff); ++ F(2, 6, 3, 0x3ffffff); ++ F(3, 9, 5, 0x1ffffff); ++ F(4, 12, 6, 0x3ffffff); ++ F(5, 16, 0, 0x1ffffff); ++ F(6, 19, 1, 0x3ffffff); ++ F(7, 22, 3, 0x1ffffff); ++ F(8, 25, 4, 0x3ffffff); ++ F(9, 28, 6, 0x1ffffff); ++#undef F ++} ++ ++#if (-32 >> 1) != -16 ++#error "This code only works when >> does sign-extension on negative numbers" ++#endif ++ ++/* s32_eq returns 0xffffffff iff a == b and zero otherwise. */ ++static s32 s32_eq(s32 a, s32 b) ++{ ++ a = ~(a ^ b); ++ a &= a << 16; ++ a &= a << 8; ++ a &= a << 4; ++ a &= a << 2; ++ a &= a << 1; ++ return a >> 31; ++} ++ ++/* s32_gte returns 0xffffffff if a >= b and zero otherwise, where a and b are ++ * both non-negative. */ ++static s32 s32_gte(s32 a, s32 b) ++{ ++ a -= b; ++ /* a >= 0 iff a >= b. */ ++ return ~(a >> 31); ++} ++ ++/* Take a fully reduced polynomial form number and contract it into a ++ * little-endian, 32-byte array. ++ * ++ * On entry: |input_limbs[i]| < 2^26 */ ++static void fcontract(u8 *output, limb *input_limbs) ++{ ++ int i; ++ int j; ++ s32 input[10]; ++ s32 mask; ++ ++ /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ ++ for (i = 0; i < 10; i++) { ++ input[i] = input_limbs[i]; ++ } ++ ++ for (j = 0; j < 2; ++j) { ++ for (i = 0; i < 9; ++i) { ++ if ((i & 1) == 1) { ++ /* This calculation is a time-invariant way to make input[i] ++ * non-negative by borrowing from the next-larger limb. */ ++ const s32 mask = input[i] >> 31; ++ const s32 carry = -((input[i] & mask) >> 25); ++ input[i] = input[i] + (carry << 25); ++ input[i+1] = input[i+1] - carry; ++ } else { ++ const s32 mask = input[i] >> 31; ++ const s32 carry = -((input[i] & mask) >> 26); ++ input[i] = input[i] + (carry << 26); ++ input[i+1] = input[i+1] - carry; ++ } ++ } ++ ++ /* There's no greater limb for input[9] to borrow from, but we can multiply ++ * by 19 and borrow from input[0], which is valid mod 2^255-19. */ ++ { ++ const s32 mask = input[9] >> 31; ++ const s32 carry = -((input[9] & mask) >> 25); ++ input[9] = input[9] + (carry << 25); ++ input[0] = input[0] - (carry * 19); ++ } ++ ++ /* After the first iteration, input[1..9] are non-negative and fit within ++ * 25 or 26 bits, depending on position. However, input[0] may be ++ * negative. */ ++ } ++ ++ /* The first borrow-propagation pass above ended with every limb ++ except (possibly) input[0] non-negative. ++ If input[0] was negative after the first pass, then it was because of a ++ carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, ++ one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. ++ In the second pass, each limb is decreased by at most one. Thus the second ++ borrow-propagation pass could only have wrapped around to decrease ++ input[0] again if the first pass left input[0] negative *and* input[1] ++ through input[9] were all zero. In that case, input[1] is now 2^25 - 1, ++ and this last borrow-propagation step will leave input[1] non-negative. */ ++ { ++ const s32 mask = input[0] >> 31; ++ const s32 carry = -((input[0] & mask) >> 26); ++ input[0] = input[0] + (carry << 26); ++ input[1] = input[1] - carry; ++ } ++ ++ /* All input[i] are now non-negative. However, there might be values between ++ * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ ++ for (j = 0; j < 2; j++) { ++ for (i = 0; i < 9; i++) { ++ if ((i & 1) == 1) { ++ const s32 carry = input[i] >> 25; ++ input[i] &= 0x1ffffff; ++ input[i+1] += carry; ++ } else { ++ const s32 carry = input[i] >> 26; ++ input[i] &= 0x3ffffff; ++ input[i+1] += carry; ++ } ++ } ++ ++ { ++ const s32 carry = input[9] >> 25; ++ input[9] &= 0x1ffffff; ++ input[0] += 19*carry; ++ } ++ } ++ ++ /* If the first carry-chain pass, just above, ended up with a carry from ++ * input[9], and that caused input[0] to be out-of-bounds, then input[0] was ++ * < 2^26 + 2*19, because the carry was, at most, two. ++ * ++ * If the second pass carried from input[9] again then input[0] is < 2*19 and ++ * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ ++ ++ /* It still remains the case that input might be between 2^255-19 and 2^255. ++ * In this case, input[1..9] must take their maximum value and input[0] must ++ * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ ++ mask = s32_gte(input[0], 0x3ffffed); ++ for (i = 1; i < 10; i++) { ++ if ((i & 1) == 1) { ++ mask &= s32_eq(input[i], 0x1ffffff); ++ } else { ++ mask &= s32_eq(input[i], 0x3ffffff); ++ } ++ } ++ ++ /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus ++ * this conditionally subtracts 2^255-19. */ ++ input[0] -= mask & 0x3ffffed; ++ ++ for (i = 1; i < 10; i++) { ++ if ((i & 1) == 1) { ++ input[i] -= mask & 0x1ffffff; ++ } else { ++ input[i] -= mask & 0x3ffffff; ++ } ++ } ++ ++ input[1] <<= 2; ++ input[2] <<= 3; ++ input[3] <<= 5; ++ input[4] <<= 6; ++ input[6] <<= 1; ++ input[7] <<= 3; ++ input[8] <<= 4; ++ input[9] <<= 6; ++#define F(i, s) \ ++ output[s+0] |= input[i] & 0xff; \ ++ output[s+1] = (input[i] >> 8) & 0xff; \ ++ output[s+2] = (input[i] >> 16) & 0xff; \ ++ output[s+3] = (input[i] >> 24) & 0xff; ++ output[0] = 0; ++ output[16] = 0; ++ F(0,0); ++ F(1,3); ++ F(2,6); ++ F(3,9); ++ F(4,12); ++ F(5,16); ++ F(6,19); ++ F(7,22); ++ F(8,25); ++ F(9,28); ++#undef F ++} ++ ++/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave ++ * them unchanged if 'iswap' is 0. Runs in data-invariant time to avoid ++ * side-channel attacks. ++ * ++ * NOTE that this function requires that 'iswap' be 1 or 0; other values give ++ * wrong results. Also, the two limb arrays must be in reduced-coefficient, ++ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped, ++ * and all all values in a[0..9],b[0..9] must have magnitude less than ++ * INT32_MAX. */ ++static void swap_conditional(limb a[19], limb b[19], limb iswap) ++{ ++ unsigned i; ++ const s32 swap = (s32) -iswap; ++ ++ for (i = 0; i < 10; ++i) { ++ const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); ++ a[i] = ((s32)a[i]) ^ x; ++ b[i] = ((s32)b[i]) ^ x; ++ } ++} ++ ++static void crecip(limb *out, const limb *z) ++{ ++ limb z2[10]; ++ limb z9[10]; ++ limb z11[10]; ++ limb z2_5_0[10]; ++ limb z2_10_0[10]; ++ limb z2_20_0[10]; ++ limb z2_50_0[10]; ++ limb z2_100_0[10]; ++ limb t0[10]; ++ limb t1[10]; ++ int i; ++ ++ /* 2 */ fsquare(z2,z); ++ /* 4 */ fsquare(t1,z2); ++ /* 8 */ fsquare(t0,t1); ++ /* 9 */ fmul(z9,t0,z); ++ /* 11 */ fmul(z11,z9,z2); ++ /* 22 */ fsquare(t0,z11); ++ /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); ++ ++ /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); ++ /* 2^7 - 2^2 */ fsquare(t1,t0); ++ /* 2^8 - 2^3 */ fsquare(t0,t1); ++ /* 2^9 - 2^4 */ fsquare(t1,t0); ++ /* 2^10 - 2^5 */ fsquare(t0,t1); ++ /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); ++ ++ /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); ++ /* 2^12 - 2^2 */ fsquare(t1,t0); ++ /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); ++ ++ /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); ++ /* 2^22 - 2^2 */ fsquare(t1,t0); ++ /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); ++ ++ /* 2^41 - 2^1 */ fsquare(t1,t0); ++ /* 2^42 - 2^2 */ fsquare(t0,t1); ++ /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { fsquare(t1,t0); fsquare(t0,t1); } ++ /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); ++ ++ /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); ++ /* 2^52 - 2^2 */ fsquare(t1,t0); ++ /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); ++ ++ /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); ++ /* 2^102 - 2^2 */ fsquare(t0,t1); ++ /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { fsquare(t1,t0); fsquare(t0,t1); } ++ /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); ++ ++ /* 2^201 - 2^1 */ fsquare(t0,t1); ++ /* 2^202 - 2^2 */ fsquare(t1,t0); ++ /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { fsquare(t0,t1); fsquare(t1,t0); } ++ /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); ++ ++ /* 2^251 - 2^1 */ fsquare(t1,t0); ++ /* 2^252 - 2^2 */ fsquare(t0,t1); ++ /* 2^253 - 2^3 */ fsquare(t1,t0); ++ /* 2^254 - 2^4 */ fsquare(t0,t1); ++ /* 2^255 - 2^5 */ fsquare(t1,t0); ++ /* 2^255 - 21 */ fmul(out,t1,z11); ++} ++ ++ ++/* Input: Q, Q', Q-Q' ++ * Output: 2Q, Q+Q' ++ * ++ * x2 z3: long form ++ * x3 z3: long form ++ * x z: short form, destroyed ++ * xprime zprime: short form, destroyed ++ * qmqp: short form, preserved ++ * ++ * On entry and exit, the absolute value of the limbs of all inputs and outputs ++ * are < 2^26. */ ++static void fmonty(limb *x2, limb *z2, /* output 2Q */ ++ limb *x3, limb *z3, /* output Q + Q' */ ++ limb *x, limb *z, /* input Q */ ++ limb *xprime, limb *zprime, /* input Q' */ ++ const limb *qmqp /* input Q - Q' */) ++{ ++ limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], ++ zzprime[19], zzzprime[19], xxxprime[19]; ++ ++ memcpy(origx, x, 10 * sizeof(limb)); ++ fsum(x, z); ++ /* |x[i]| < 2^27 */ ++ fdifference(z, origx); /* does x - z */ ++ /* |z[i]| < 2^27 */ ++ ++ memcpy(origxprime, xprime, sizeof(limb) * 10); ++ fsum(xprime, zprime); ++ /* |xprime[i]| < 2^27 */ ++ fdifference(zprime, origxprime); ++ /* |zprime[i]| < 2^27 */ ++ fproduct(xxprime, xprime, z); ++ /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < ++ * 2^(27+27) and fproduct adds together, at most, 14 of those products. ++ * (Approximating that to 2^58 doesn't work out.) */ ++ fproduct(zzprime, x, zprime); ++ /* |zzprime[i]| < 14*2^54 */ ++ freduce_degree(xxprime); ++ freduce_coefficients(xxprime); ++ /* |xxprime[i]| < 2^26 */ ++ freduce_degree(zzprime); ++ freduce_coefficients(zzprime); ++ /* |zzprime[i]| < 2^26 */ ++ memcpy(origxprime, xxprime, sizeof(limb) * 10); ++ fsum(xxprime, zzprime); ++ /* |xxprime[i]| < 2^27 */ ++ fdifference(zzprime, origxprime); ++ /* |zzprime[i]| < 2^27 */ ++ fsquare(xxxprime, xxprime); ++ /* |xxxprime[i]| < 2^26 */ ++ fsquare(zzzprime, zzprime); ++ /* |zzzprime[i]| < 2^26 */ ++ fproduct(zzprime, zzzprime, qmqp); ++ /* |zzprime[i]| < 14*2^52 */ ++ freduce_degree(zzprime); ++ freduce_coefficients(zzprime); ++ /* |zzprime[i]| < 2^26 */ ++ memcpy(x3, xxxprime, sizeof(limb) * 10); ++ memcpy(z3, zzprime, sizeof(limb) * 10); ++ ++ fsquare(xx, x); ++ /* |xx[i]| < 2^26 */ ++ fsquare(zz, z); ++ /* |zz[i]| < 2^26 */ ++ fproduct(x2, xx, zz); ++ /* |x2[i]| < 14*2^52 */ ++ freduce_degree(x2); ++ freduce_coefficients(x2); ++ /* |x2[i]| < 2^26 */ ++ fdifference(zz, xx); // does zz = xx - zz ++ /* |zz[i]| < 2^27 */ ++ memset(zzz + 10, 0, sizeof(limb) * 9); ++ fscalar_product(zzz, zz, 121665); ++ /* |zzz[i]| < 2^(27+17) */ ++ /* No need to call freduce_degree here: ++ fscalar_product doesn't increase the degree of its input. */ ++ freduce_coefficients(zzz); ++ /* |zzz[i]| < 2^26 */ ++ fsum(zzz, xx); ++ /* |zzz[i]| < 2^27 */ ++ fproduct(z2, zz, zzz); ++ /* |z2[i]| < 14*2^(26+27) */ ++ freduce_degree(z2); ++ freduce_coefficients(z2); ++ /* |z2|i| < 2^26 */ ++} ++ ++/* Calculates nQ where Q is the x-coordinate of a point on the curve ++ * ++ * resultx/resultz: the x coordinate of the resulting curve point (short form) ++ * n: a little endian, 32-byte number ++ * q: a point of the curve (short form) */ ++static void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) ++{ ++ limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; ++ limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; ++ limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; ++ limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; ++ ++ unsigned i, j; ++ ++ memcpy(nqpqx, q, sizeof(limb) * 10); ++ ++ for (i = 0; i < 32; ++i) { ++ u8 byte = n[31 - i]; ++ for (j = 0; j < 8; ++j) { ++ const limb bit = byte >> 7; ++ ++ swap_conditional(nqx, nqpqx, bit); ++ swap_conditional(nqz, nqpqz, bit); ++ fmonty(nqx2, nqz2, ++ nqpqx2, nqpqz2, ++ nqx, nqz, ++ nqpqx, nqpqz, ++ q); ++ swap_conditional(nqx2, nqpqx2, bit); ++ swap_conditional(nqz2, nqpqz2, bit); ++ ++ t = nqx; ++ nqx = nqx2; ++ nqx2 = t; ++ t = nqz; ++ nqz = nqz2; ++ nqz2 = t; ++ t = nqpqx; ++ nqpqx = nqpqx2; ++ nqpqx2 = t; ++ t = nqpqz; ++ nqpqz = nqpqz2; ++ nqpqz2 = t; ++ ++ byte <<= 1; ++ } ++ } ++ ++ memcpy(resultx, nqx, sizeof(limb) * 10); ++ memcpy(resultz, nqz, sizeof(limb) * 10); ++} ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]) ++{ ++ limb bp[10], x[10], z[11], zmone[10]; ++ u8 e[32]; ++ ++ memcpy(e, secret, 32); ++ normalize_secret(e); ++ ++ fexpand(bp, basepoint); ++ cmult(x, z, e, bp); ++ crecip(zmone, z); ++ fmul(z, x, zmone); ++ fcontract(mypublic, z); ++ ++ memzero_explicit(e, sizeof(e)); ++ memzero_explicit(bp, sizeof(bp)); ++ memzero_explicit(x, sizeof(x)); ++ memzero_explicit(z, sizeof(z)); ++ memzero_explicit(zmone, sizeof(zmone)); ++} ++#endif ++ ++void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ get_random_bytes(secret, CURVE25519_POINT_SIZE); ++ normalize_secret(secret); ++} ++ ++void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE]) ++{ ++ static const u8 basepoint[CURVE25519_POINT_SIZE] = { 9 }; ++ curve25519(pub, secret, basepoint); ++} ++ ++#include "../selftest/curve25519.h" +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/blake2s.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,36 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef BLAKE2S_H ++#define BLAKE2S_H ++ ++#include ++ ++enum blake2s_lengths { ++ BLAKE2S_BLOCKBYTES = 64, ++ BLAKE2S_OUTBYTES = 32, ++ BLAKE2S_KEYBYTES = 32 ++}; ++ ++struct blake2s_state { ++ u32 h[8]; ++ u32 t[2]; ++ u32 f[2]; ++ u8 buf[2 * BLAKE2S_BLOCKBYTES]; ++ size_t buflen; ++ u8 last_node; ++}; ++ ++void blake2s(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u8 keylen); ++ ++void blake2s_init(struct blake2s_state *state, const u8 outlen); ++void blake2s_init_key(struct blake2s_state *state, const u8 outlen, const void *key, const u8 keylen); ++void blake2s_update(struct blake2s_state *state, const u8 *in, u64 inlen); ++void blake2s_final(struct blake2s_state *state, u8 *out, u8 outlen); ++ ++void blake2s_hmac(u8 *out, const u8 *in, const u8 *key, const u8 outlen, const u64 inlen, const u64 keylen); ++ ++#ifdef DEBUG ++bool blake2s_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20poly1305.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,78 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef CHACHA20POLY1305_H ++#define CHACHA20POLY1305_H ++ ++#include ++ ++struct scatterlist; ++ ++enum chacha20poly1305_lengths { ++ XCHACHA20POLY1305_NONCELEN = 24, ++ CHACHA20POLY1305_KEYLEN = 32, ++ CHACHA20POLY1305_AUTHTAGLEN = 16 ++}; ++ ++void chacha20poly1305_init(void); ++ ++bool chacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool chacha20poly1305_encrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN], ++ bool have_simd); ++ ++bool chacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool chacha20poly1305_decrypt_sg(struct scatterlist *dst, struct scatterlist *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u64 nonce, const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool xchacha20poly1305_encrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++bool xchacha20poly1305_decrypt(u8 *dst, const u8 *src, const size_t src_len, ++ const u8 *ad, const size_t ad_len, ++ const u8 nonce[XCHACHA20POLY1305_NONCELEN], ++ const u8 key[CHACHA20POLY1305_KEYLEN]); ++ ++#ifdef CONFIG_X86_64 ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) ++#include ++#include ++#else ++#include ++#endif ++#endif ++ ++static inline bool chacha20poly1305_init_simd(void) ++{ ++ bool have_simd = false; ++#ifdef CONFIG_X86_64 ++ have_simd = irq_fpu_usable(); ++ if (have_simd) ++ kernel_fpu_begin(); ++#endif ++ return have_simd; ++} ++ ++static inline void chacha20poly1305_deinit_simd(bool was_on) ++{ ++#ifdef CONFIG_X86_64 ++ if (was_on) ++ kernel_fpu_end(); ++#endif ++} ++ ++#ifdef DEBUG ++bool chacha20poly1305_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/curve25519.h 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,20 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef CURVE25519_H ++#define CURVE25519_H ++ ++#include ++ ++enum curve25519_lengths { ++ CURVE25519_POINT_SIZE = 32 ++}; ++ ++void curve25519(u8 mypublic[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE], const u8 basepoint[CURVE25519_POINT_SIZE]); ++void curve25519_generate_secret(u8 secret[CURVE25519_POINT_SIZE]); ++void curve25519_generate_public(u8 pub[CURVE25519_POINT_SIZE], const u8 secret[CURVE25519_POINT_SIZE]); ++ ++#ifdef DEBUG ++bool curve25519_selftest(void); ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20-avx2-x86_64.S 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,443 @@ ++/* ++ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 AVX2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 32 ++ ++ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003 ++ .octa 0x0e0d0c0f0a09080b0605040702010003 ++ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302 ++ .octa 0x0d0c0f0e09080b0a0504070601000302 ++CTRINC: .octa 0x00000003000000020000000100000000 ++ .octa 0x00000007000000060000000500000004 ++ ++.text ++ ++ENTRY(chacha20_asm_8block_xor_avx2) ++ # %rdi: Input state matrix, s ++ # %rsi: 8 data blocks output, o ++ # %rdx: 8 data blocks input, i ++ ++ # This function encrypts eight consecutive ChaCha20 blocks by loading ++ # the state matrix in AVX registers eight times. As we need some ++ # scratch registers, we save the first four registers on the stack. The ++ # algorithm performs each operation on the corresponding word of each ++ # state matrix, hence requires no word shuffling. For final XORing step ++ # we transpose the matrix by interleaving 32-, 64- and then 128-bit ++ # words, which allows us to do XOR in AVX registers. 8/16-bit word ++ # rotation is done with the slightly better performing byte shuffling, ++ # 7/12-bit word rotation uses traditional shift+OR. ++ ++ vzeroupper ++ # 4 * 32 byte stack, 32-byte aligned ++ mov %rsp, %r8 ++ and $~31, %rsp ++ sub $0x80, %rsp ++ ++ # x0..15[0-7] = s[0..15] ++ vpbroadcastd 0x00(%rdi),%ymm0 ++ vpbroadcastd 0x04(%rdi),%ymm1 ++ vpbroadcastd 0x08(%rdi),%ymm2 ++ vpbroadcastd 0x0c(%rdi),%ymm3 ++ vpbroadcastd 0x10(%rdi),%ymm4 ++ vpbroadcastd 0x14(%rdi),%ymm5 ++ vpbroadcastd 0x18(%rdi),%ymm6 ++ vpbroadcastd 0x1c(%rdi),%ymm7 ++ vpbroadcastd 0x20(%rdi),%ymm8 ++ vpbroadcastd 0x24(%rdi),%ymm9 ++ vpbroadcastd 0x28(%rdi),%ymm10 ++ vpbroadcastd 0x2c(%rdi),%ymm11 ++ vpbroadcastd 0x30(%rdi),%ymm12 ++ vpbroadcastd 0x34(%rdi),%ymm13 ++ vpbroadcastd 0x38(%rdi),%ymm14 ++ vpbroadcastd 0x3c(%rdi),%ymm15 ++ # x0..3 on stack ++ vmovdqa %ymm0,0x00(%rsp) ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa %ymm3,0x60(%rsp) ++ ++ vmovdqa CTRINC(%rip),%ymm1 ++ vmovdqa ROT8(%rip),%ymm2 ++ vmovdqa ROT16(%rip),%ymm3 ++ ++ # x12 += counter values 0-3 ++ vpaddd %ymm1,%ymm12,%ymm12 ++ ++ mov $10,%ecx ++ ++.Ldoubleround8: ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 16) ++ vpaddd 0x00(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm3,%ymm12,%ymm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 16) ++ vpaddd 0x20(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm3,%ymm13,%ymm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 16) ++ vpaddd 0x40(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm3,%ymm14,%ymm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 16) ++ vpaddd 0x60(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm3,%ymm15,%ymm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 12) ++ vpaddd %ymm12,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm4,%ymm4 ++ vpslld $12,%ymm4,%ymm0 ++ vpsrld $20,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 12) ++ vpaddd %ymm13,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm5,%ymm5 ++ vpslld $12,%ymm5,%ymm0 ++ vpsrld $20,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 12) ++ vpaddd %ymm14,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm6,%ymm6 ++ vpslld $12,%ymm6,%ymm0 ++ vpsrld $20,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 12) ++ vpaddd %ymm15,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm7,%ymm7 ++ vpslld $12,%ymm7,%ymm0 ++ vpsrld $20,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 8) ++ vpaddd 0x00(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm2,%ymm12,%ymm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 8) ++ vpaddd 0x20(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm2,%ymm13,%ymm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 8) ++ vpaddd 0x40(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm2,%ymm14,%ymm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 8) ++ vpaddd 0x60(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm2,%ymm15,%ymm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 7) ++ vpaddd %ymm12,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm4,%ymm4 ++ vpslld $7,%ymm4,%ymm0 ++ vpsrld $25,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 7) ++ vpaddd %ymm13,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm5,%ymm5 ++ vpslld $7,%ymm5,%ymm0 ++ vpsrld $25,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 7) ++ vpaddd %ymm14,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm6,%ymm6 ++ vpslld $7,%ymm6,%ymm0 ++ vpsrld $25,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 7) ++ vpaddd %ymm15,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm7,%ymm7 ++ vpslld $7,%ymm7,%ymm0 ++ vpsrld $25,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 16) ++ vpaddd 0x00(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm3,%ymm15,%ymm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 16)%ymm0 ++ vpaddd 0x20(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm3,%ymm12,%ymm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 16) ++ vpaddd 0x40(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm3,%ymm13,%ymm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 16) ++ vpaddd 0x60(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm3,%ymm14,%ymm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 12) ++ vpaddd %ymm15,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm5,%ymm5 ++ vpslld $12,%ymm5,%ymm0 ++ vpsrld $20,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 12) ++ vpaddd %ymm12,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm6,%ymm6 ++ vpslld $12,%ymm6,%ymm0 ++ vpsrld $20,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 12) ++ vpaddd %ymm13,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm7,%ymm7 ++ vpslld $12,%ymm7,%ymm0 ++ vpsrld $20,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 12) ++ vpaddd %ymm14,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm4,%ymm4 ++ vpslld $12,%ymm4,%ymm0 ++ vpsrld $20,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 8) ++ vpaddd 0x00(%rsp),%ymm5,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpxor %ymm0,%ymm15,%ymm15 ++ vpshufb %ymm2,%ymm15,%ymm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 8) ++ vpaddd 0x20(%rsp),%ymm6,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpxor %ymm0,%ymm12,%ymm12 ++ vpshufb %ymm2,%ymm12,%ymm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 8) ++ vpaddd 0x40(%rsp),%ymm7,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpxor %ymm0,%ymm13,%ymm13 ++ vpshufb %ymm2,%ymm13,%ymm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 8) ++ vpaddd 0x60(%rsp),%ymm4,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpxor %ymm0,%ymm14,%ymm14 ++ vpshufb %ymm2,%ymm14,%ymm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 7) ++ vpaddd %ymm15,%ymm10,%ymm10 ++ vpxor %ymm10,%ymm5,%ymm5 ++ vpslld $7,%ymm5,%ymm0 ++ vpsrld $25,%ymm5,%ymm5 ++ vpor %ymm0,%ymm5,%ymm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 7) ++ vpaddd %ymm12,%ymm11,%ymm11 ++ vpxor %ymm11,%ymm6,%ymm6 ++ vpslld $7,%ymm6,%ymm0 ++ vpsrld $25,%ymm6,%ymm6 ++ vpor %ymm0,%ymm6,%ymm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 7) ++ vpaddd %ymm13,%ymm8,%ymm8 ++ vpxor %ymm8,%ymm7,%ymm7 ++ vpslld $7,%ymm7,%ymm0 ++ vpsrld $25,%ymm7,%ymm7 ++ vpor %ymm0,%ymm7,%ymm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 7) ++ vpaddd %ymm14,%ymm9,%ymm9 ++ vpxor %ymm9,%ymm4,%ymm4 ++ vpslld $7,%ymm4,%ymm0 ++ vpsrld $25,%ymm4,%ymm4 ++ vpor %ymm0,%ymm4,%ymm4 ++ ++ dec %ecx ++ jnz .Ldoubleround8 ++ ++ # x0..15[0-3] += s[0..15] ++ vpbroadcastd 0x00(%rdi),%ymm0 ++ vpaddd 0x00(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x00(%rsp) ++ vpbroadcastd 0x04(%rdi),%ymm0 ++ vpaddd 0x20(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x20(%rsp) ++ vpbroadcastd 0x08(%rdi),%ymm0 ++ vpaddd 0x40(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x40(%rsp) ++ vpbroadcastd 0x0c(%rdi),%ymm0 ++ vpaddd 0x60(%rsp),%ymm0,%ymm0 ++ vmovdqa %ymm0,0x60(%rsp) ++ vpbroadcastd 0x10(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm4,%ymm4 ++ vpbroadcastd 0x14(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm5,%ymm5 ++ vpbroadcastd 0x18(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm6,%ymm6 ++ vpbroadcastd 0x1c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm7,%ymm7 ++ vpbroadcastd 0x20(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm8,%ymm8 ++ vpbroadcastd 0x24(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm9,%ymm9 ++ vpbroadcastd 0x28(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm10,%ymm10 ++ vpbroadcastd 0x2c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm11,%ymm11 ++ vpbroadcastd 0x30(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm12,%ymm12 ++ vpbroadcastd 0x34(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm13,%ymm13 ++ vpbroadcastd 0x38(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm14,%ymm14 ++ vpbroadcastd 0x3c(%rdi),%ymm0 ++ vpaddd %ymm0,%ymm15,%ymm15 ++ ++ # x12 += counter values 0-3 ++ vpaddd %ymm1,%ymm12,%ymm12 ++ ++ # interleave 32-bit words in state n, n+1 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vmovdqa 0x20(%rsp),%ymm1 ++ vpunpckldq %ymm1,%ymm0,%ymm2 ++ vpunpckhdq %ymm1,%ymm0,%ymm1 ++ vmovdqa %ymm2,0x00(%rsp) ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vmovdqa 0x60(%rsp),%ymm1 ++ vpunpckldq %ymm1,%ymm0,%ymm2 ++ vpunpckhdq %ymm1,%ymm0,%ymm1 ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa %ymm1,0x60(%rsp) ++ vmovdqa %ymm4,%ymm0 ++ vpunpckldq %ymm5,%ymm0,%ymm4 ++ vpunpckhdq %ymm5,%ymm0,%ymm5 ++ vmovdqa %ymm6,%ymm0 ++ vpunpckldq %ymm7,%ymm0,%ymm6 ++ vpunpckhdq %ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm8,%ymm0 ++ vpunpckldq %ymm9,%ymm0,%ymm8 ++ vpunpckhdq %ymm9,%ymm0,%ymm9 ++ vmovdqa %ymm10,%ymm0 ++ vpunpckldq %ymm11,%ymm0,%ymm10 ++ vpunpckhdq %ymm11,%ymm0,%ymm11 ++ vmovdqa %ymm12,%ymm0 ++ vpunpckldq %ymm13,%ymm0,%ymm12 ++ vpunpckhdq %ymm13,%ymm0,%ymm13 ++ vmovdqa %ymm14,%ymm0 ++ vpunpckldq %ymm15,%ymm0,%ymm14 ++ vpunpckhdq %ymm15,%ymm0,%ymm15 ++ ++ # interleave 64-bit words in state n, n+2 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vmovdqa 0x40(%rsp),%ymm2 ++ vpunpcklqdq %ymm2,%ymm0,%ymm1 ++ vpunpckhqdq %ymm2,%ymm0,%ymm2 ++ vmovdqa %ymm1,0x00(%rsp) ++ vmovdqa %ymm2,0x40(%rsp) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vmovdqa 0x60(%rsp),%ymm2 ++ vpunpcklqdq %ymm2,%ymm0,%ymm1 ++ vpunpckhqdq %ymm2,%ymm0,%ymm2 ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa %ymm2,0x60(%rsp) ++ vmovdqa %ymm4,%ymm0 ++ vpunpcklqdq %ymm6,%ymm0,%ymm4 ++ vpunpckhqdq %ymm6,%ymm0,%ymm6 ++ vmovdqa %ymm5,%ymm0 ++ vpunpcklqdq %ymm7,%ymm0,%ymm5 ++ vpunpckhqdq %ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm8,%ymm0 ++ vpunpcklqdq %ymm10,%ymm0,%ymm8 ++ vpunpckhqdq %ymm10,%ymm0,%ymm10 ++ vmovdqa %ymm9,%ymm0 ++ vpunpcklqdq %ymm11,%ymm0,%ymm9 ++ vpunpckhqdq %ymm11,%ymm0,%ymm11 ++ vmovdqa %ymm12,%ymm0 ++ vpunpcklqdq %ymm14,%ymm0,%ymm12 ++ vpunpckhqdq %ymm14,%ymm0,%ymm14 ++ vmovdqa %ymm13,%ymm0 ++ vpunpcklqdq %ymm15,%ymm0,%ymm13 ++ vpunpckhqdq %ymm15,%ymm0,%ymm15 ++ ++ # interleave 128-bit words in state n, n+4 ++ vmovdqa 0x00(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm4,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm4,%ymm0,%ymm4 ++ vmovdqa %ymm1,0x00(%rsp) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm5,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm5,%ymm0,%ymm5 ++ vmovdqa %ymm1,0x20(%rsp) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm6,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm6,%ymm0,%ymm6 ++ vmovdqa %ymm1,0x40(%rsp) ++ vmovdqa 0x60(%rsp),%ymm0 ++ vperm2i128 $0x20,%ymm7,%ymm0,%ymm1 ++ vperm2i128 $0x31,%ymm7,%ymm0,%ymm7 ++ vmovdqa %ymm1,0x60(%rsp) ++ vperm2i128 $0x20,%ymm12,%ymm8,%ymm0 ++ vperm2i128 $0x31,%ymm12,%ymm8,%ymm12 ++ vmovdqa %ymm0,%ymm8 ++ vperm2i128 $0x20,%ymm13,%ymm9,%ymm0 ++ vperm2i128 $0x31,%ymm13,%ymm9,%ymm13 ++ vmovdqa %ymm0,%ymm9 ++ vperm2i128 $0x20,%ymm14,%ymm10,%ymm0 ++ vperm2i128 $0x31,%ymm14,%ymm10,%ymm14 ++ vmovdqa %ymm0,%ymm10 ++ vperm2i128 $0x20,%ymm15,%ymm11,%ymm0 ++ vperm2i128 $0x31,%ymm15,%ymm11,%ymm15 ++ vmovdqa %ymm0,%ymm11 ++ ++ # xor with corresponding input, write to output ++ vmovdqa 0x00(%rsp),%ymm0 ++ vpxor 0x0000(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0000(%rsi) ++ vmovdqa 0x20(%rsp),%ymm0 ++ vpxor 0x0080(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0080(%rsi) ++ vmovdqa 0x40(%rsp),%ymm0 ++ vpxor 0x0040(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x0040(%rsi) ++ vmovdqa 0x60(%rsp),%ymm0 ++ vpxor 0x00c0(%rdx),%ymm0,%ymm0 ++ vmovdqu %ymm0,0x00c0(%rsi) ++ vpxor 0x0100(%rdx),%ymm4,%ymm4 ++ vmovdqu %ymm4,0x0100(%rsi) ++ vpxor 0x0180(%rdx),%ymm5,%ymm5 ++ vmovdqu %ymm5,0x00180(%rsi) ++ vpxor 0x0140(%rdx),%ymm6,%ymm6 ++ vmovdqu %ymm6,0x0140(%rsi) ++ vpxor 0x01c0(%rdx),%ymm7,%ymm7 ++ vmovdqu %ymm7,0x01c0(%rsi) ++ vpxor 0x0020(%rdx),%ymm8,%ymm8 ++ vmovdqu %ymm8,0x0020(%rsi) ++ vpxor 0x00a0(%rdx),%ymm9,%ymm9 ++ vmovdqu %ymm9,0x00a0(%rsi) ++ vpxor 0x0060(%rdx),%ymm10,%ymm10 ++ vmovdqu %ymm10,0x0060(%rsi) ++ vpxor 0x00e0(%rdx),%ymm11,%ymm11 ++ vmovdqu %ymm11,0x00e0(%rsi) ++ vpxor 0x0120(%rdx),%ymm12,%ymm12 ++ vmovdqu %ymm12,0x0120(%rsi) ++ vpxor 0x01a0(%rdx),%ymm13,%ymm13 ++ vmovdqu %ymm13,0x01a0(%rsi) ++ vpxor 0x0160(%rdx),%ymm14,%ymm14 ++ vmovdqu %ymm14,0x0160(%rsi) ++ vpxor 0x01e0(%rdx),%ymm15,%ymm15 ++ vmovdqu %ymm15,0x01e0(%rsi) ++ ++ vzeroupper ++ mov %r8,%rsp ++ ret ++ENDPROC(chacha20_asm_8block_xor_avx2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/chacha20-ssse3-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,627 @@ ++/* ++ * ChaCha20 256-bit cipher algorithm, RFC7539, x64 SSSE3 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 16 ++ ++ROT8: .octa 0x0e0d0c0f0a09080b0605040702010003 ++ROT16: .octa 0x0d0c0f0e09080b0a0504070601000302 ++CTRINC: .octa 0x00000003000000020000000100000000 ++ ++.text ++ ++ENTRY(chacha20_asm_block_xor_ssse3) ++ # %rdi: Input state matrix, s ++ # %rsi: 1 data block output, o ++ # %rdx: 1 data block input, i ++ ++ # This function encrypts one ChaCha20 block by loading the state matrix ++ # in four SSE registers. It performs matrix operation on four words in ++ # parallel, but requireds shuffling to rearrange the words after each ++ # round. 8/16-bit word rotation is done with the slightly better ++ # performing SSSE3 byte shuffling, 7/12-bit word rotation uses ++ # traditional shift+OR. ++ ++ # x0..3 = s0..3 ++ movdqa 0x00(%rdi),%xmm0 ++ movdqa 0x10(%rdi),%xmm1 ++ movdqa 0x20(%rdi),%xmm2 ++ movdqa 0x30(%rdi),%xmm3 ++ movdqa %xmm0,%xmm8 ++ movdqa %xmm1,%xmm9 ++ movdqa %xmm2,%xmm10 ++ movdqa %xmm3,%xmm11 ++ ++ movdqa ROT8(%rip),%xmm4 ++ movdqa ROT16(%rip),%xmm5 ++ ++ mov $10,%ecx ++ ++.Ldoubleround: ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 16) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm5,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 12) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm6 ++ pslld $12,%xmm6 ++ psrld $20,%xmm1 ++ por %xmm6,%xmm1 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 8) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm4,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 7) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm7 ++ pslld $7,%xmm7 ++ psrld $25,%xmm1 ++ por %xmm7,%xmm1 ++ ++ # x1 = shuffle32(x1, MASK(0, 3, 2, 1)) ++ pshufd $0x39,%xmm1,%xmm1 ++ # x2 = shuffle32(x2, MASK(1, 0, 3, 2)) ++ pshufd $0x4e,%xmm2,%xmm2 ++ # x3 = shuffle32(x3, MASK(2, 1, 0, 3)) ++ pshufd $0x93,%xmm3,%xmm3 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 16) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm5,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 12) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm6 ++ pslld $12,%xmm6 ++ psrld $20,%xmm1 ++ por %xmm6,%xmm1 ++ ++ # x0 += x1, x3 = rotl32(x3 ^ x0, 8) ++ paddd %xmm1,%xmm0 ++ pxor %xmm0,%xmm3 ++ pshufb %xmm4,%xmm3 ++ ++ # x2 += x3, x1 = rotl32(x1 ^ x2, 7) ++ paddd %xmm3,%xmm2 ++ pxor %xmm2,%xmm1 ++ movdqa %xmm1,%xmm7 ++ pslld $7,%xmm7 ++ psrld $25,%xmm1 ++ por %xmm7,%xmm1 ++ ++ # x1 = shuffle32(x1, MASK(2, 1, 0, 3)) ++ pshufd $0x93,%xmm1,%xmm1 ++ # x2 = shuffle32(x2, MASK(1, 0, 3, 2)) ++ pshufd $0x4e,%xmm2,%xmm2 ++ # x3 = shuffle32(x3, MASK(0, 3, 2, 1)) ++ pshufd $0x39,%xmm3,%xmm3 ++ ++ dec %ecx ++ jnz .Ldoubleround ++ ++ # o0 = i0 ^ (x0 + s0) ++ movdqu 0x00(%rdx),%xmm4 ++ paddd %xmm8,%xmm0 ++ pxor %xmm4,%xmm0 ++ movdqu %xmm0,0x00(%rsi) ++ # o1 = i1 ^ (x1 + s1) ++ movdqu 0x10(%rdx),%xmm5 ++ paddd %xmm9,%xmm1 ++ pxor %xmm5,%xmm1 ++ movdqu %xmm1,0x10(%rsi) ++ # o2 = i2 ^ (x2 + s2) ++ movdqu 0x20(%rdx),%xmm6 ++ paddd %xmm10,%xmm2 ++ pxor %xmm6,%xmm2 ++ movdqu %xmm2,0x20(%rsi) ++ # o3 = i3 ^ (x3 + s3) ++ movdqu 0x30(%rdx),%xmm7 ++ paddd %xmm11,%xmm3 ++ pxor %xmm7,%xmm3 ++ movdqu %xmm3,0x30(%rsi) ++ ++ ret ++ENDPROC(chacha20_asm_block_xor_ssse3) ++ ++ENTRY(chacha20_asm_4block_xor_ssse3) ++ # %rdi: Input state matrix, s ++ # %rsi: 4 data blocks output, o ++ # %rdx: 4 data blocks input, i ++ ++ # This function encrypts four consecutive ChaCha20 blocks by loading the ++ # the state matrix in SSE registers four times. As we need some scratch ++ # registers, we save the first four registers on the stack. The ++ # algorithm performs each operation on the corresponding word of each ++ # state matrix, hence requires no word shuffling. For final XORing step ++ # we transpose the matrix by interleaving 32- and then 64-bit words, ++ # which allows us to do XOR in SSE registers. 8/16-bit word rotation is ++ # done with the slightly better performing SSSE3 byte shuffling, ++ # 7/12-bit word rotation uses traditional shift+OR. ++ ++ mov %rsp,%r11 ++ sub $0x80,%rsp ++ and $~63,%rsp ++ ++ # x0..15[0-3] = s0..3[0..3] ++ movq 0x00(%rdi),%xmm1 ++ pshufd $0x00,%xmm1,%xmm0 ++ pshufd $0x55,%xmm1,%xmm1 ++ movq 0x08(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ movq 0x10(%rdi),%xmm5 ++ pshufd $0x00,%xmm5,%xmm4 ++ pshufd $0x55,%xmm5,%xmm5 ++ movq 0x18(%rdi),%xmm7 ++ pshufd $0x00,%xmm7,%xmm6 ++ pshufd $0x55,%xmm7,%xmm7 ++ movq 0x20(%rdi),%xmm9 ++ pshufd $0x00,%xmm9,%xmm8 ++ pshufd $0x55,%xmm9,%xmm9 ++ movq 0x28(%rdi),%xmm11 ++ pshufd $0x00,%xmm11,%xmm10 ++ pshufd $0x55,%xmm11,%xmm11 ++ movq 0x30(%rdi),%xmm13 ++ pshufd $0x00,%xmm13,%xmm12 ++ pshufd $0x55,%xmm13,%xmm13 ++ movq 0x38(%rdi),%xmm15 ++ pshufd $0x00,%xmm15,%xmm14 ++ pshufd $0x55,%xmm15,%xmm15 ++ # x0..3 on stack ++ movdqa %xmm0,0x00(%rsp) ++ movdqa %xmm1,0x10(%rsp) ++ movdqa %xmm2,0x20(%rsp) ++ movdqa %xmm3,0x30(%rsp) ++ ++ movdqa CTRINC(%rip),%xmm1 ++ movdqa ROT8(%rip),%xmm2 ++ movdqa ROT16(%rip),%xmm3 ++ ++ # x12 += counter values 0-3 ++ paddd %xmm1,%xmm12 ++ ++ mov $10,%ecx ++ ++.Ldoubleround4: ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 16) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm3,%xmm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 16) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm3,%xmm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 16) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm3,%xmm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 16) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm3,%xmm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 12) ++ paddd %xmm12,%xmm8 ++ pxor %xmm8,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm4 ++ por %xmm0,%xmm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 12) ++ paddd %xmm13,%xmm9 ++ pxor %xmm9,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm5 ++ por %xmm0,%xmm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 12) ++ paddd %xmm14,%xmm10 ++ pxor %xmm10,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm6 ++ por %xmm0,%xmm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 12) ++ paddd %xmm15,%xmm11 ++ pxor %xmm11,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm7 ++ por %xmm0,%xmm7 ++ ++ # x0 += x4, x12 = rotl32(x12 ^ x0, 8) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm2,%xmm12 ++ # x1 += x5, x13 = rotl32(x13 ^ x1, 8) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm2,%xmm13 ++ # x2 += x6, x14 = rotl32(x14 ^ x2, 8) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm2,%xmm14 ++ # x3 += x7, x15 = rotl32(x15 ^ x3, 8) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm2,%xmm15 ++ ++ # x8 += x12, x4 = rotl32(x4 ^ x8, 7) ++ paddd %xmm12,%xmm8 ++ pxor %xmm8,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm4 ++ por %xmm0,%xmm4 ++ # x9 += x13, x5 = rotl32(x5 ^ x9, 7) ++ paddd %xmm13,%xmm9 ++ pxor %xmm9,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm5 ++ por %xmm0,%xmm5 ++ # x10 += x14, x6 = rotl32(x6 ^ x10, 7) ++ paddd %xmm14,%xmm10 ++ pxor %xmm10,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm6 ++ por %xmm0,%xmm6 ++ # x11 += x15, x7 = rotl32(x7 ^ x11, 7) ++ paddd %xmm15,%xmm11 ++ pxor %xmm11,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm7 ++ por %xmm0,%xmm7 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 16) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm3,%xmm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 16) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm3,%xmm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 16) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm3,%xmm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 16) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm3,%xmm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 12) ++ paddd %xmm15,%xmm10 ++ pxor %xmm10,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm5 ++ por %xmm0,%xmm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 12) ++ paddd %xmm12,%xmm11 ++ pxor %xmm11,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm6 ++ por %xmm0,%xmm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 12) ++ paddd %xmm13,%xmm8 ++ pxor %xmm8,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm7 ++ por %xmm0,%xmm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 12) ++ paddd %xmm14,%xmm9 ++ pxor %xmm9,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $12,%xmm0 ++ psrld $20,%xmm4 ++ por %xmm0,%xmm4 ++ ++ # x0 += x5, x15 = rotl32(x15 ^ x0, 8) ++ movdqa 0x00(%rsp),%xmm0 ++ paddd %xmm5,%xmm0 ++ movdqa %xmm0,0x00(%rsp) ++ pxor %xmm0,%xmm15 ++ pshufb %xmm2,%xmm15 ++ # x1 += x6, x12 = rotl32(x12 ^ x1, 8) ++ movdqa 0x10(%rsp),%xmm0 ++ paddd %xmm6,%xmm0 ++ movdqa %xmm0,0x10(%rsp) ++ pxor %xmm0,%xmm12 ++ pshufb %xmm2,%xmm12 ++ # x2 += x7, x13 = rotl32(x13 ^ x2, 8) ++ movdqa 0x20(%rsp),%xmm0 ++ paddd %xmm7,%xmm0 ++ movdqa %xmm0,0x20(%rsp) ++ pxor %xmm0,%xmm13 ++ pshufb %xmm2,%xmm13 ++ # x3 += x4, x14 = rotl32(x14 ^ x3, 8) ++ movdqa 0x30(%rsp),%xmm0 ++ paddd %xmm4,%xmm0 ++ movdqa %xmm0,0x30(%rsp) ++ pxor %xmm0,%xmm14 ++ pshufb %xmm2,%xmm14 ++ ++ # x10 += x15, x5 = rotl32(x5 ^ x10, 7) ++ paddd %xmm15,%xmm10 ++ pxor %xmm10,%xmm5 ++ movdqa %xmm5,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm5 ++ por %xmm0,%xmm5 ++ # x11 += x12, x6 = rotl32(x6 ^ x11, 7) ++ paddd %xmm12,%xmm11 ++ pxor %xmm11,%xmm6 ++ movdqa %xmm6,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm6 ++ por %xmm0,%xmm6 ++ # x8 += x13, x7 = rotl32(x7 ^ x8, 7) ++ paddd %xmm13,%xmm8 ++ pxor %xmm8,%xmm7 ++ movdqa %xmm7,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm7 ++ por %xmm0,%xmm7 ++ # x9 += x14, x4 = rotl32(x4 ^ x9, 7) ++ paddd %xmm14,%xmm9 ++ pxor %xmm9,%xmm4 ++ movdqa %xmm4,%xmm0 ++ pslld $7,%xmm0 ++ psrld $25,%xmm4 ++ por %xmm0,%xmm4 ++ ++ dec %ecx ++ jnz .Ldoubleround4 ++ ++ # x0[0-3] += s0[0] ++ # x1[0-3] += s0[1] ++ movq 0x00(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd 0x00(%rsp),%xmm2 ++ movdqa %xmm2,0x00(%rsp) ++ paddd 0x10(%rsp),%xmm3 ++ movdqa %xmm3,0x10(%rsp) ++ # x2[0-3] += s0[2] ++ # x3[0-3] += s0[3] ++ movq 0x08(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd 0x20(%rsp),%xmm2 ++ movdqa %xmm2,0x20(%rsp) ++ paddd 0x30(%rsp),%xmm3 ++ movdqa %xmm3,0x30(%rsp) ++ ++ # x4[0-3] += s1[0] ++ # x5[0-3] += s1[1] ++ movq 0x10(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm4 ++ paddd %xmm3,%xmm5 ++ # x6[0-3] += s1[2] ++ # x7[0-3] += s1[3] ++ movq 0x18(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm6 ++ paddd %xmm3,%xmm7 ++ ++ # x8[0-3] += s2[0] ++ # x9[0-3] += s2[1] ++ movq 0x20(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm8 ++ paddd %xmm3,%xmm9 ++ # x10[0-3] += s2[2] ++ # x11[0-3] += s2[3] ++ movq 0x28(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm10 ++ paddd %xmm3,%xmm11 ++ ++ # x12[0-3] += s3[0] ++ # x13[0-3] += s3[1] ++ movq 0x30(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm12 ++ paddd %xmm3,%xmm13 ++ # x14[0-3] += s3[2] ++ # x15[0-3] += s3[3] ++ movq 0x38(%rdi),%xmm3 ++ pshufd $0x00,%xmm3,%xmm2 ++ pshufd $0x55,%xmm3,%xmm3 ++ paddd %xmm2,%xmm14 ++ paddd %xmm3,%xmm15 ++ ++ # x12 += counter values 0-3 ++ paddd %xmm1,%xmm12 ++ ++ # interleave 32-bit words in state n, n+1 ++ movdqa 0x00(%rsp),%xmm0 ++ movdqa 0x10(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpckldq %xmm1,%xmm2 ++ punpckhdq %xmm1,%xmm0 ++ movdqa %xmm2,0x00(%rsp) ++ movdqa %xmm0,0x10(%rsp) ++ movdqa 0x20(%rsp),%xmm0 ++ movdqa 0x30(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpckldq %xmm1,%xmm2 ++ punpckhdq %xmm1,%xmm0 ++ movdqa %xmm2,0x20(%rsp) ++ movdqa %xmm0,0x30(%rsp) ++ movdqa %xmm4,%xmm0 ++ punpckldq %xmm5,%xmm4 ++ punpckhdq %xmm5,%xmm0 ++ movdqa %xmm0,%xmm5 ++ movdqa %xmm6,%xmm0 ++ punpckldq %xmm7,%xmm6 ++ punpckhdq %xmm7,%xmm0 ++ movdqa %xmm0,%xmm7 ++ movdqa %xmm8,%xmm0 ++ punpckldq %xmm9,%xmm8 ++ punpckhdq %xmm9,%xmm0 ++ movdqa %xmm0,%xmm9 ++ movdqa %xmm10,%xmm0 ++ punpckldq %xmm11,%xmm10 ++ punpckhdq %xmm11,%xmm0 ++ movdqa %xmm0,%xmm11 ++ movdqa %xmm12,%xmm0 ++ punpckldq %xmm13,%xmm12 ++ punpckhdq %xmm13,%xmm0 ++ movdqa %xmm0,%xmm13 ++ movdqa %xmm14,%xmm0 ++ punpckldq %xmm15,%xmm14 ++ punpckhdq %xmm15,%xmm0 ++ movdqa %xmm0,%xmm15 ++ ++ # interleave 64-bit words in state n, n+2 ++ movdqa 0x00(%rsp),%xmm0 ++ movdqa 0x20(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpcklqdq %xmm1,%xmm2 ++ punpckhqdq %xmm1,%xmm0 ++ movdqa %xmm2,0x00(%rsp) ++ movdqa %xmm0,0x20(%rsp) ++ movdqa 0x10(%rsp),%xmm0 ++ movdqa 0x30(%rsp),%xmm1 ++ movdqa %xmm0,%xmm2 ++ punpcklqdq %xmm1,%xmm2 ++ punpckhqdq %xmm1,%xmm0 ++ movdqa %xmm2,0x10(%rsp) ++ movdqa %xmm0,0x30(%rsp) ++ movdqa %xmm4,%xmm0 ++ punpcklqdq %xmm6,%xmm4 ++ punpckhqdq %xmm6,%xmm0 ++ movdqa %xmm0,%xmm6 ++ movdqa %xmm5,%xmm0 ++ punpcklqdq %xmm7,%xmm5 ++ punpckhqdq %xmm7,%xmm0 ++ movdqa %xmm0,%xmm7 ++ movdqa %xmm8,%xmm0 ++ punpcklqdq %xmm10,%xmm8 ++ punpckhqdq %xmm10,%xmm0 ++ movdqa %xmm0,%xmm10 ++ movdqa %xmm9,%xmm0 ++ punpcklqdq %xmm11,%xmm9 ++ punpckhqdq %xmm11,%xmm0 ++ movdqa %xmm0,%xmm11 ++ movdqa %xmm12,%xmm0 ++ punpcklqdq %xmm14,%xmm12 ++ punpckhqdq %xmm14,%xmm0 ++ movdqa %xmm0,%xmm14 ++ movdqa %xmm13,%xmm0 ++ punpcklqdq %xmm15,%xmm13 ++ punpckhqdq %xmm15,%xmm0 ++ movdqa %xmm0,%xmm15 ++ ++ # xor with corresponding input, write to output ++ movdqa 0x00(%rsp),%xmm0 ++ movdqu 0x00(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x00(%rsi) ++ movdqa 0x10(%rsp),%xmm0 ++ movdqu 0x80(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x80(%rsi) ++ movdqa 0x20(%rsp),%xmm0 ++ movdqu 0x40(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0x40(%rsi) ++ movdqa 0x30(%rsp),%xmm0 ++ movdqu 0xc0(%rdx),%xmm1 ++ pxor %xmm1,%xmm0 ++ movdqu %xmm0,0xc0(%rsi) ++ movdqu 0x10(%rdx),%xmm1 ++ pxor %xmm1,%xmm4 ++ movdqu %xmm4,0x10(%rsi) ++ movdqu 0x90(%rdx),%xmm1 ++ pxor %xmm1,%xmm5 ++ movdqu %xmm5,0x90(%rsi) ++ movdqu 0x50(%rdx),%xmm1 ++ pxor %xmm1,%xmm6 ++ movdqu %xmm6,0x50(%rsi) ++ movdqu 0xd0(%rdx),%xmm1 ++ pxor %xmm1,%xmm7 ++ movdqu %xmm7,0xd0(%rsi) ++ movdqu 0x20(%rdx),%xmm1 ++ pxor %xmm1,%xmm8 ++ movdqu %xmm8,0x20(%rsi) ++ movdqu 0xa0(%rdx),%xmm1 ++ pxor %xmm1,%xmm9 ++ movdqu %xmm9,0xa0(%rsi) ++ movdqu 0x60(%rdx),%xmm1 ++ pxor %xmm1,%xmm10 ++ movdqu %xmm10,0x60(%rsi) ++ movdqu 0xe0(%rdx),%xmm1 ++ pxor %xmm1,%xmm11 ++ movdqu %xmm11,0xe0(%rsi) ++ movdqu 0x30(%rdx),%xmm1 ++ pxor %xmm1,%xmm12 ++ movdqu %xmm12,0x30(%rsi) ++ movdqu 0xb0(%rdx),%xmm1 ++ pxor %xmm1,%xmm13 ++ movdqu %xmm13,0xb0(%rsi) ++ movdqu 0x70(%rdx),%xmm1 ++ pxor %xmm1,%xmm14 ++ movdqu %xmm14,0x70(%rsi) ++ movdqu 0xf0(%rdx),%xmm1 ++ pxor %xmm1,%xmm15 ++ movdqu %xmm15,0xf0(%rsi) ++ ++ mov %r11,%rsp ++ ret ++ENDPROC(chacha20_asm_4block_xor_ssse3) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/poly1305-avx2-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,386 @@ ++/* ++ * Poly1305 authenticator algorithm, RFC7539, x64 AVX2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 32 ++ ++ANMASK: .octa 0x0000000003ffffff0000000003ffffff ++ .octa 0x0000000003ffffff0000000003ffffff ++ORMASK: .octa 0x00000000010000000000000001000000 ++ .octa 0x00000000010000000000000001000000 ++ ++.text ++ ++#define h0 0x00(%rdi) ++#define h1 0x04(%rdi) ++#define h2 0x08(%rdi) ++#define h3 0x0c(%rdi) ++#define h4 0x10(%rdi) ++#define r0 0x00(%rdx) ++#define r1 0x04(%rdx) ++#define r2 0x08(%rdx) ++#define r3 0x0c(%rdx) ++#define r4 0x10(%rdx) ++#define u0 0x00(%r8) ++#define u1 0x04(%r8) ++#define u2 0x08(%r8) ++#define u3 0x0c(%r8) ++#define u4 0x10(%r8) ++#define w0 0x14(%r8) ++#define w1 0x18(%r8) ++#define w2 0x1c(%r8) ++#define w3 0x20(%r8) ++#define w4 0x24(%r8) ++#define y0 0x28(%r8) ++#define y1 0x2c(%r8) ++#define y2 0x30(%r8) ++#define y3 0x34(%r8) ++#define y4 0x38(%r8) ++#define m %rsi ++#define hc0 %ymm0 ++#define hc1 %ymm1 ++#define hc2 %ymm2 ++#define hc3 %ymm3 ++#define hc4 %ymm4 ++#define hc0x %xmm0 ++#define hc1x %xmm1 ++#define hc2x %xmm2 ++#define hc3x %xmm3 ++#define hc4x %xmm4 ++#define t1 %ymm5 ++#define t2 %ymm6 ++#define t1x %xmm5 ++#define t2x %xmm6 ++#define ruwy0 %ymm7 ++#define ruwy1 %ymm8 ++#define ruwy2 %ymm9 ++#define ruwy3 %ymm10 ++#define ruwy4 %ymm11 ++#define ruwy0x %xmm7 ++#define ruwy1x %xmm8 ++#define ruwy2x %xmm9 ++#define ruwy3x %xmm10 ++#define ruwy4x %xmm11 ++#define svxz1 %ymm12 ++#define svxz2 %ymm13 ++#define svxz3 %ymm14 ++#define svxz4 %ymm15 ++#define d0 %r9 ++#define d1 %r10 ++#define d2 %r11 ++#define d3 %r12 ++#define d4 %r13 ++ ++ENTRY(poly1305_asm_4block_avx2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 64 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Quadblock count ++ # %r8: Poly1305 derived key r^2 u[5], r^3 w[5], r^4 y[5], ++ ++ # This four-block variant uses loop unrolled block processing. It ++ # requires 4 Poly1305 keys: r, r^2, r^3 and r^4: ++ # h = (h + m) * r => h = (h + m1) * r^4 + m2 * r^3 + m3 * r^2 + m4 * r ++ ++ vzeroupper ++ push %rbx ++ push %r12 ++ push %r13 ++ ++ # combine r0,u0,w0,y0 ++ vmovd y0,ruwy0x ++ vmovd w0,t1x ++ vpunpcklqdq t1,ruwy0,ruwy0 ++ vmovd u0,t1x ++ vmovd r0,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy0,ruwy0 ++ ++ # combine r1,u1,w1,y1 and s1=r1*5,v1=u1*5,x1=w1*5,z1=y1*5 ++ vmovd y1,ruwy1x ++ vmovd w1,t1x ++ vpunpcklqdq t1,ruwy1,ruwy1 ++ vmovd u1,t1x ++ vmovd r1,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy1,ruwy1 ++ vpslld $2,ruwy1,svxz1 ++ vpaddd ruwy1,svxz1,svxz1 ++ ++ # combine r2,u2,w2,y2 and s2=r2*5,v2=u2*5,x2=w2*5,z2=y2*5 ++ vmovd y2,ruwy2x ++ vmovd w2,t1x ++ vpunpcklqdq t1,ruwy2,ruwy2 ++ vmovd u2,t1x ++ vmovd r2,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy2,ruwy2 ++ vpslld $2,ruwy2,svxz2 ++ vpaddd ruwy2,svxz2,svxz2 ++ ++ # combine r3,u3,w3,y3 and s3=r3*5,v3=u3*5,x3=w3*5,z3=y3*5 ++ vmovd y3,ruwy3x ++ vmovd w3,t1x ++ vpunpcklqdq t1,ruwy3,ruwy3 ++ vmovd u3,t1x ++ vmovd r3,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy3,ruwy3 ++ vpslld $2,ruwy3,svxz3 ++ vpaddd ruwy3,svxz3,svxz3 ++ ++ # combine r4,u4,w4,y4 and s4=r4*5,v4=u4*5,x4=w4*5,z4=y4*5 ++ vmovd y4,ruwy4x ++ vmovd w4,t1x ++ vpunpcklqdq t1,ruwy4,ruwy4 ++ vmovd u4,t1x ++ vmovd r4,t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,ruwy4,ruwy4 ++ vpslld $2,ruwy4,svxz4 ++ vpaddd ruwy4,svxz4,svxz4 ++ ++.Ldoblock4: ++ # hc0 = [m[48-51] & 0x3ffffff, m[32-35] & 0x3ffffff, ++ # m[16-19] & 0x3ffffff, m[ 0- 3] & 0x3ffffff + h0] ++ vmovd 0x00(m),hc0x ++ vmovd 0x10(m),t1x ++ vpunpcklqdq t1,hc0,hc0 ++ vmovd 0x20(m),t1x ++ vmovd 0x30(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc0,hc0 ++ vpand ANMASK(%rip),hc0,hc0 ++ vmovd h0,t1x ++ vpaddd t1,hc0,hc0 ++ # hc1 = [(m[51-54] >> 2) & 0x3ffffff, (m[35-38] >> 2) & 0x3ffffff, ++ # (m[19-22] >> 2) & 0x3ffffff, (m[ 3- 6] >> 2) & 0x3ffffff + h1] ++ vmovd 0x03(m),hc1x ++ vmovd 0x13(m),t1x ++ vpunpcklqdq t1,hc1,hc1 ++ vmovd 0x23(m),t1x ++ vmovd 0x33(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc1,hc1 ++ vpsrld $2,hc1,hc1 ++ vpand ANMASK(%rip),hc1,hc1 ++ vmovd h1,t1x ++ vpaddd t1,hc1,hc1 ++ # hc2 = [(m[54-57] >> 4) & 0x3ffffff, (m[38-41] >> 4) & 0x3ffffff, ++ # (m[22-25] >> 4) & 0x3ffffff, (m[ 6- 9] >> 4) & 0x3ffffff + h2] ++ vmovd 0x06(m),hc2x ++ vmovd 0x16(m),t1x ++ vpunpcklqdq t1,hc2,hc2 ++ vmovd 0x26(m),t1x ++ vmovd 0x36(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc2,hc2 ++ vpsrld $4,hc2,hc2 ++ vpand ANMASK(%rip),hc2,hc2 ++ vmovd h2,t1x ++ vpaddd t1,hc2,hc2 ++ # hc3 = [(m[57-60] >> 6) & 0x3ffffff, (m[41-44] >> 6) & 0x3ffffff, ++ # (m[25-28] >> 6) & 0x3ffffff, (m[ 9-12] >> 6) & 0x3ffffff + h3] ++ vmovd 0x09(m),hc3x ++ vmovd 0x19(m),t1x ++ vpunpcklqdq t1,hc3,hc3 ++ vmovd 0x29(m),t1x ++ vmovd 0x39(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc3,hc3 ++ vpsrld $6,hc3,hc3 ++ vpand ANMASK(%rip),hc3,hc3 ++ vmovd h3,t1x ++ vpaddd t1,hc3,hc3 ++ # hc4 = [(m[60-63] >> 8) | (1<<24), (m[44-47] >> 8) | (1<<24), ++ # (m[28-31] >> 8) | (1<<24), (m[12-15] >> 8) | (1<<24) + h4] ++ vmovd 0x0c(m),hc4x ++ vmovd 0x1c(m),t1x ++ vpunpcklqdq t1,hc4,hc4 ++ vmovd 0x2c(m),t1x ++ vmovd 0x3c(m),t2x ++ vpunpcklqdq t2,t1,t1 ++ vperm2i128 $0x20,t1,hc4,hc4 ++ vpsrld $8,hc4,hc4 ++ vpor ORMASK(%rip),hc4,hc4 ++ vmovd h4,t1x ++ vpaddd t1,hc4,hc4 ++ ++ # t1 = [ hc0[3] * r0, hc0[2] * u0, hc0[1] * w0, hc0[0] * y0 ] ++ vpmuludq hc0,ruwy0,t1 ++ # t1 += [ hc1[3] * s4, hc1[2] * v4, hc1[1] * x4, hc1[0] * z4 ] ++ vpmuludq hc1,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * s3, hc2[2] * v3, hc2[1] * x3, hc2[0] * z3 ] ++ vpmuludq hc2,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s2, hc3[2] * v2, hc3[1] * x2, hc3[0] * z2 ] ++ vpmuludq hc3,svxz2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s1, hc4[2] * v1, hc4[1] * x1, hc4[0] * z1 ] ++ vpmuludq hc4,svxz1,t2 ++ vpaddq t2,t1,t1 ++ # d0 = t1[0] + t1[1] + t[2] + t[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d0 ++ ++ # t1 = [ hc0[3] * r1, hc0[2] * u1,hc0[1] * w1, hc0[0] * y1 ] ++ vpmuludq hc0,ruwy1,t1 ++ # t1 += [ hc1[3] * r0, hc1[2] * u0, hc1[1] * w0, hc1[0] * y0 ] ++ vpmuludq hc1,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * s4, hc2[2] * v4, hc2[1] * x4, hc2[0] * z4 ] ++ vpmuludq hc2,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s3, hc3[2] * v3, hc3[1] * x3, hc3[0] * z3 ] ++ vpmuludq hc3,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s2, hc4[2] * v2, hc4[1] * x2, hc4[0] * z2 ] ++ vpmuludq hc4,svxz2,t2 ++ vpaddq t2,t1,t1 ++ # d1 = t1[0] + t1[1] + t1[3] + t1[4] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d1 ++ ++ # t1 = [ hc0[3] * r2, hc0[2] * u2, hc0[1] * w2, hc0[0] * y2 ] ++ vpmuludq hc0,ruwy2,t1 ++ # t1 += [ hc1[3] * r1, hc1[2] * u1, hc1[1] * w1, hc1[0] * y1 ] ++ vpmuludq hc1,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r0, hc2[2] * u0, hc2[1] * w0, hc2[0] * y0 ] ++ vpmuludq hc2,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * s4, hc3[2] * v4, hc3[1] * x4, hc3[0] * z4 ] ++ vpmuludq hc3,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s3, hc4[2] * v3, hc4[1] * x3, hc4[0] * z3 ] ++ vpmuludq hc4,svxz3,t2 ++ vpaddq t2,t1,t1 ++ # d2 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d2 ++ ++ # t1 = [ hc0[3] * r3, hc0[2] * u3, hc0[1] * w3, hc0[0] * y3 ] ++ vpmuludq hc0,ruwy3,t1 ++ # t1 += [ hc1[3] * r2, hc1[2] * u2, hc1[1] * w2, hc1[0] * y2 ] ++ vpmuludq hc1,ruwy2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r1, hc2[2] * u1, hc2[1] * w1, hc2[0] * y1 ] ++ vpmuludq hc2,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * r0, hc3[2] * u0, hc3[1] * w0, hc3[0] * y0 ] ++ vpmuludq hc3,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * s4, hc4[2] * v4, hc4[1] * x4, hc4[0] * z4 ] ++ vpmuludq hc4,svxz4,t2 ++ vpaddq t2,t1,t1 ++ # d3 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d3 ++ ++ # t1 = [ hc0[3] * r4, hc0[2] * u4, hc0[1] * w4, hc0[0] * y4 ] ++ vpmuludq hc0,ruwy4,t1 ++ # t1 += [ hc1[3] * r3, hc1[2] * u3, hc1[1] * w3, hc1[0] * y3 ] ++ vpmuludq hc1,ruwy3,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc2[3] * r2, hc2[2] * u2, hc2[1] * w2, hc2[0] * y2 ] ++ vpmuludq hc2,ruwy2,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc3[3] * r1, hc3[2] * u1, hc3[1] * w1, hc3[0] * y1 ] ++ vpmuludq hc3,ruwy1,t2 ++ vpaddq t2,t1,t1 ++ # t1 += [ hc4[3] * r0, hc4[2] * u0, hc4[1] * w0, hc4[0] * y0 ] ++ vpmuludq hc4,ruwy0,t2 ++ vpaddq t2,t1,t1 ++ # d4 = t1[0] + t1[1] + t1[2] + t1[3] ++ vpermq $0xee,t1,t2 ++ vpaddq t2,t1,t1 ++ vpsrldq $8,t1,t2 ++ vpaddq t2,t1,t1 ++ vmovq t1x,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x40,m ++ dec %rcx ++ jnz .Ldoblock4 ++ ++ vzeroupper ++ pop %r13 ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_4block_avx2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/crypto/poly1305-sse2-x86_64.S 2017-03-05 17:03:41.526682408 +0200 +@@ -0,0 +1,582 @@ ++/* ++ * Poly1305 authenticator algorithm, RFC7539, x64 SSE2 functions ++ * ++ * Copyright (C) 2015 Martin Willi ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++ ++.data ++.align 16 ++ ++ANMASK: .octa 0x0000000003ffffff0000000003ffffff ++ORMASK: .octa 0x00000000010000000000000001000000 ++ ++.text ++ ++#define h0 0x00(%rdi) ++#define h1 0x04(%rdi) ++#define h2 0x08(%rdi) ++#define h3 0x0c(%rdi) ++#define h4 0x10(%rdi) ++#define r0 0x00(%rdx) ++#define r1 0x04(%rdx) ++#define r2 0x08(%rdx) ++#define r3 0x0c(%rdx) ++#define r4 0x10(%rdx) ++#define s1 0x00(%rsp) ++#define s2 0x04(%rsp) ++#define s3 0x08(%rsp) ++#define s4 0x0c(%rsp) ++#define m %rsi ++#define h01 %xmm0 ++#define h23 %xmm1 ++#define h44 %xmm2 ++#define t1 %xmm3 ++#define t2 %xmm4 ++#define t3 %xmm5 ++#define t4 %xmm6 ++#define mask %xmm7 ++#define d0 %r8 ++#define d1 %r9 ++#define d2 %r10 ++#define d3 %r11 ++#define d4 %r12 ++ ++ENTRY(poly1305_asm_block_sse2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 16 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Block count ++ ++ # This single block variant tries to improve performance by doing two ++ # multiplications in parallel using SSE instructions. There is quite ++ # some quardword packing involved, hence the speedup is marginal. ++ ++ push %rbx ++ push %r12 ++ sub $0x10,%rsp ++ ++ # s1..s4 = r1..r4 * 5 ++ mov r1,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s1 ++ mov r2,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s2 ++ mov r3,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s3 ++ mov r4,%eax ++ lea (%eax,%eax,4),%eax ++ mov %eax,s4 ++ ++ movdqa ANMASK(%rip),mask ++ ++.Ldoblock: ++ # h01 = [0, h1, 0, h0] ++ # h23 = [0, h3, 0, h2] ++ # h44 = [0, h4, 0, h4] ++ movd h0,h01 ++ movd h1,t1 ++ movd h2,h23 ++ movd h3,t2 ++ movd h4,h44 ++ punpcklqdq t1,h01 ++ punpcklqdq t2,h23 ++ punpcklqdq h44,h44 ++ ++ # h01 += [ (m[3-6] >> 2) & 0x3ffffff, m[0-3] & 0x3ffffff ] ++ movd 0x00(m),t1 ++ movd 0x03(m),t2 ++ psrld $2,t2 ++ punpcklqdq t2,t1 ++ pand mask,t1 ++ paddd t1,h01 ++ # h23 += [ (m[9-12] >> 6) & 0x3ffffff, (m[6-9] >> 4) & 0x3ffffff ] ++ movd 0x06(m),t1 ++ movd 0x09(m),t2 ++ psrld $4,t1 ++ psrld $6,t2 ++ punpcklqdq t2,t1 ++ pand mask,t1 ++ paddd t1,h23 ++ # h44 += [ (m[12-15] >> 8) | (1 << 24), (m[12-15] >> 8) | (1 << 24) ] ++ mov 0x0c(m),%eax ++ shr $8,%eax ++ or $0x01000000,%eax ++ movd %eax,t1 ++ pshufd $0xc4,t1,t1 ++ paddd t1,h44 ++ ++ # t1[0] = h0 * r0 + h2 * s3 ++ # t1[1] = h1 * s4 + h3 * s2 ++ movd r0,t1 ++ movd s4,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd s3,t2 ++ movd s2,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t2[0] = h0 * r1 + h2 * s4 ++ # t2[1] = h1 * r0 + h3 * s3 ++ movd r1,t2 ++ movd r0,t3 ++ punpcklqdq t3,t2 ++ pmuludq h01,t2 ++ movd s4,t3 ++ movd s3,t4 ++ punpcklqdq t4,t3 ++ pmuludq h23,t3 ++ paddq t3,t2 ++ # t3[0] = h4 * s1 ++ # t3[1] = h4 * s2 ++ movd s1,t3 ++ movd s2,t4 ++ punpcklqdq t4,t3 ++ pmuludq h44,t3 ++ # d0 = t1[0] + t1[1] + t3[0] ++ # d1 = t2[0] + t2[1] + t3[1] ++ movdqa t1,t4 ++ punpcklqdq t2,t4 ++ punpckhqdq t2,t1 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d0 ++ psrldq $8,t1 ++ movq t1,d1 ++ ++ # t1[0] = h0 * r2 + h2 * r0 ++ # t1[1] = h1 * r1 + h3 * s4 ++ movd r2,t1 ++ movd r1,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd r0,t2 ++ movd s4,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t2[0] = h0 * r3 + h2 * r1 ++ # t2[1] = h1 * r2 + h3 * r0 ++ movd r3,t2 ++ movd r2,t3 ++ punpcklqdq t3,t2 ++ pmuludq h01,t2 ++ movd r1,t3 ++ movd r0,t4 ++ punpcklqdq t4,t3 ++ pmuludq h23,t3 ++ paddq t3,t2 ++ # t3[0] = h4 * s3 ++ # t3[1] = h4 * s4 ++ movd s3,t3 ++ movd s4,t4 ++ punpcklqdq t4,t3 ++ pmuludq h44,t3 ++ # d2 = t1[0] + t1[1] + t3[0] ++ # d3 = t2[0] + t2[1] + t3[1] ++ movdqa t1,t4 ++ punpcklqdq t2,t4 ++ punpckhqdq t2,t1 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d2 ++ psrldq $8,t1 ++ movq t1,d3 ++ ++ # t1[0] = h0 * r4 + h2 * r2 ++ # t1[1] = h1 * r3 + h3 * r1 ++ movd r4,t1 ++ movd r3,t2 ++ punpcklqdq t2,t1 ++ pmuludq h01,t1 ++ movd r2,t2 ++ movd r1,t3 ++ punpcklqdq t3,t2 ++ pmuludq h23,t2 ++ paddq t2,t1 ++ # t3[0] = h4 * r0 ++ movd r0,t3 ++ pmuludq h44,t3 ++ # d4 = t1[0] + t1[1] + t3[0] ++ movdqa t1,t4 ++ psrldq $8,t4 ++ paddq t4,t1 ++ paddq t3,t1 ++ movq t1,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x10,m ++ dec %rcx ++ jnz .Ldoblock ++ ++ add $0x10,%rsp ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_block_sse2) ++ ++ ++#define u0 0x00(%r8) ++#define u1 0x04(%r8) ++#define u2 0x08(%r8) ++#define u3 0x0c(%r8) ++#define u4 0x10(%r8) ++#define hc0 %xmm0 ++#define hc1 %xmm1 ++#define hc2 %xmm2 ++#define hc3 %xmm5 ++#define hc4 %xmm6 ++#define ru0 %xmm7 ++#define ru1 %xmm8 ++#define ru2 %xmm9 ++#define ru3 %xmm10 ++#define ru4 %xmm11 ++#define sv1 %xmm12 ++#define sv2 %xmm13 ++#define sv3 %xmm14 ++#define sv4 %xmm15 ++#undef d0 ++#define d0 %r13 ++ ++ENTRY(poly1305_asm_2block_sse2) ++ # %rdi: Accumulator h[5] ++ # %rsi: 16 byte input block m ++ # %rdx: Poly1305 key r[5] ++ # %rcx: Doubleblock count ++ # %r8: Poly1305 derived key r^2 u[5] ++ ++ # This two-block variant further improves performance by using loop ++ # unrolled block processing. This is more straight forward and does ++ # less byte shuffling, but requires a second Poly1305 key r^2: ++ # h = (h + m) * r => h = (h + m1) * r^2 + m2 * r ++ ++ push %rbx ++ push %r12 ++ push %r13 ++ ++ # combine r0,u0 ++ movd u0,ru0 ++ movd r0,t1 ++ punpcklqdq t1,ru0 ++ ++ # combine r1,u1 and s1=r1*5,v1=u1*5 ++ movd u1,ru1 ++ movd r1,t1 ++ punpcklqdq t1,ru1 ++ movdqa ru1,sv1 ++ pslld $2,sv1 ++ paddd ru1,sv1 ++ ++ # combine r2,u2 and s2=r2*5,v2=u2*5 ++ movd u2,ru2 ++ movd r2,t1 ++ punpcklqdq t1,ru2 ++ movdqa ru2,sv2 ++ pslld $2,sv2 ++ paddd ru2,sv2 ++ ++ # combine r3,u3 and s3=r3*5,v3=u3*5 ++ movd u3,ru3 ++ movd r3,t1 ++ punpcklqdq t1,ru3 ++ movdqa ru3,sv3 ++ pslld $2,sv3 ++ paddd ru3,sv3 ++ ++ # combine r4,u4 and s4=r4*5,v4=u4*5 ++ movd u4,ru4 ++ movd r4,t1 ++ punpcklqdq t1,ru4 ++ movdqa ru4,sv4 ++ pslld $2,sv4 ++ paddd ru4,sv4 ++ ++.Ldoblock2: ++ # hc0 = [ m[16-19] & 0x3ffffff, h0 + m[0-3] & 0x3ffffff ] ++ movd 0x00(m),hc0 ++ movd 0x10(m),t1 ++ punpcklqdq t1,hc0 ++ pand ANMASK(%rip),hc0 ++ movd h0,t1 ++ paddd t1,hc0 ++ # hc1 = [ (m[19-22] >> 2) & 0x3ffffff, h1 + (m[3-6] >> 2) & 0x3ffffff ] ++ movd 0x03(m),hc1 ++ movd 0x13(m),t1 ++ punpcklqdq t1,hc1 ++ psrld $2,hc1 ++ pand ANMASK(%rip),hc1 ++ movd h1,t1 ++ paddd t1,hc1 ++ # hc2 = [ (m[22-25] >> 4) & 0x3ffffff, h2 + (m[6-9] >> 4) & 0x3ffffff ] ++ movd 0x06(m),hc2 ++ movd 0x16(m),t1 ++ punpcklqdq t1,hc2 ++ psrld $4,hc2 ++ pand ANMASK(%rip),hc2 ++ movd h2,t1 ++ paddd t1,hc2 ++ # hc3 = [ (m[25-28] >> 6) & 0x3ffffff, h3 + (m[9-12] >> 6) & 0x3ffffff ] ++ movd 0x09(m),hc3 ++ movd 0x19(m),t1 ++ punpcklqdq t1,hc3 ++ psrld $6,hc3 ++ pand ANMASK(%rip),hc3 ++ movd h3,t1 ++ paddd t1,hc3 ++ # hc4 = [ (m[28-31] >> 8) | (1<<24), h4 + (m[12-15] >> 8) | (1<<24) ] ++ movd 0x0c(m),hc4 ++ movd 0x1c(m),t1 ++ punpcklqdq t1,hc4 ++ psrld $8,hc4 ++ por ORMASK(%rip),hc4 ++ movd h4,t1 ++ paddd t1,hc4 ++ ++ # t1 = [ hc0[1] * r0, hc0[0] * u0 ] ++ movdqa ru0,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * s4, hc1[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * s3, hc2[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s2, hc3[0] * v2 ] ++ movdqa sv2,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s1, hc4[0] * v1 ] ++ movdqa sv1,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d0 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d0 ++ ++ # t1 = [ hc0[1] * r1, hc0[0] * u1 ] ++ movdqa ru1,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r0, hc1[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * s4, hc2[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s3, hc3[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s2, hc4[0] * v2 ] ++ movdqa sv2,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d1 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d1 ++ ++ # t1 = [ hc0[1] * r2, hc0[0] * u2 ] ++ movdqa ru2,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r1, hc1[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r0, hc2[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * s4, hc3[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s3, hc4[0] * v3 ] ++ movdqa sv3,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d2 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d2 ++ ++ # t1 = [ hc0[1] * r3, hc0[0] * u3 ] ++ movdqa ru3,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r2, hc1[0] * u2 ] ++ movdqa ru2,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r1, hc2[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * r0, hc3[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * s4, hc4[0] * v4 ] ++ movdqa sv4,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d3 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d3 ++ ++ # t1 = [ hc0[1] * r4, hc0[0] * u4 ] ++ movdqa ru4,t1 ++ pmuludq hc0,t1 ++ # t1 += [ hc1[1] * r3, hc1[0] * u3 ] ++ movdqa ru3,t2 ++ pmuludq hc1,t2 ++ paddq t2,t1 ++ # t1 += [ hc2[1] * r2, hc2[0] * u2 ] ++ movdqa ru2,t2 ++ pmuludq hc2,t2 ++ paddq t2,t1 ++ # t1 += [ hc3[1] * r1, hc3[0] * u1 ] ++ movdqa ru1,t2 ++ pmuludq hc3,t2 ++ paddq t2,t1 ++ # t1 += [ hc4[1] * r0, hc4[0] * u0 ] ++ movdqa ru0,t2 ++ pmuludq hc4,t2 ++ paddq t2,t1 ++ # d4 = t1[0] + t1[1] ++ movdqa t1,t2 ++ psrldq $8,t2 ++ paddq t2,t1 ++ movq t1,d4 ++ ++ # d1 += d0 >> 26 ++ mov d0,%rax ++ shr $26,%rax ++ add %rax,d1 ++ # h0 = d0 & 0x3ffffff ++ mov d0,%rbx ++ and $0x3ffffff,%ebx ++ ++ # d2 += d1 >> 26 ++ mov d1,%rax ++ shr $26,%rax ++ add %rax,d2 ++ # h1 = d1 & 0x3ffffff ++ mov d1,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h1 ++ ++ # d3 += d2 >> 26 ++ mov d2,%rax ++ shr $26,%rax ++ add %rax,d3 ++ # h2 = d2 & 0x3ffffff ++ mov d2,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h2 ++ ++ # d4 += d3 >> 26 ++ mov d3,%rax ++ shr $26,%rax ++ add %rax,d4 ++ # h3 = d3 & 0x3ffffff ++ mov d3,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h3 ++ ++ # h0 += (d4 >> 26) * 5 ++ mov d4,%rax ++ shr $26,%rax ++ lea (%eax,%eax,4),%eax ++ add %eax,%ebx ++ # h4 = d4 & 0x3ffffff ++ mov d4,%rax ++ and $0x3ffffff,%eax ++ mov %eax,h4 ++ ++ # h1 += h0 >> 26 ++ mov %ebx,%eax ++ shr $26,%eax ++ add %eax,h1 ++ # h0 = h0 & 0x3ffffff ++ andl $0x3ffffff,%ebx ++ mov %ebx,h0 ++ ++ add $0x20,m ++ dec %rcx ++ jnz .Ldoblock2 ++ ++ pop %r13 ++ pop %r12 ++ pop %rbx ++ ret ++ENDPROC(poly1305_asm_2block_sse2) +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/Makefile 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,36 @@ ++ccflags-y := -O3 -fvisibility=hidden ++ccflags-$(CONFIG_WIREGUARD_DEBUG) := -DDEBUG -g ++ccflags-y += -Wframe-larger-than=8192 ++ccflags-y += -D'pr_fmt(fmt)=KBUILD_MODNAME ": " fmt' ++wireguard-y := main.o noise.o device.o peer.o timers.o data.o send.o receive.o socket.o config.o hashtables.o routingtable.o ratelimiter.o cookie.o ++wireguard-y += crypto/curve25519.o crypto/chacha20poly1305.o crypto/blake2s.o ++ifeq ($(CONFIG_X86_64),y) ++ wireguard-y += crypto/chacha20-ssse3-x86_64.o crypto/poly1305-sse2-x86_64.o ++avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1$(comma)4)$(comma)%ymm2,yes,no) ++ifeq ($(avx2_supported),yes) ++ wireguard-y += crypto/chacha20-avx2-x86_64.o crypto/poly1305-avx2-x86_64.o ++endif ++endif ++ ++include $(src)/compat/Makefile.include ++ ++ifneq ($(KBUILD_EXTMOD),) ++CONFIG_WIREGUARD := m ++ifeq ($(CONFIG_WIREGUARD_PARALLEL),) ++ifneq (,$(filter $(CONFIG_PADATA),y m)) ++ccflags-y += -DCONFIG_WIREGUARD_PARALLEL=y ++endif ++endif ++ifneq ($(CONFIG_MODULES),) ++ifeq ($(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT),) ++$(error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT to be configured in your kernel. See https://www.wireguard.io/install/#kernel-requirements for more info") ++endif ++ifeq ($(CONFIG_PADATA),) ++ifneq ($(CONFIG_SMP),) ++$(warning "PEFORMANCE WARNING: WireGuard has enormous speed benefits when using CONFIG_PADATA on SMP systems. Please enable CONFIG_PADATA in your kernel configuration. See https://www.wireguard.io/install/#kernel-requirements for more info.") ++endif ++endif ++endif ++endif ++ ++obj-$(CONFIG_WIREGUARD) := wireguard.o +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/Kconfig 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,43 @@ ++config WIREGUARD ++ tristate "IP: WireGuard secure network tunnel" ++ depends on NET && INET ++ select NET_UDP_TUNNEL ++ select NETFILTER_XT_MATCH_HASHLIMIT ++ select NETFILTER ++ select NETFILTER_XTABLES ++ select NETFILTER_ADVANCED ++ select CRYPTO_BLKCIPHER ++ select IP6_NF_IPTABLES if IPV6 ++ default m ++ ---help--- ++ WireGuard is a secure, fast, and easy to use replacement for IPSec ++ that uses modern cryptography and clever networking tricks. It's ++ designed to be fairly general purpose and abstract enough to fit most ++ use cases, while at the same time remaining extremely simple to ++ configure. See www.wireguard.io for more info. ++ ++ It's safe to say Y or M here, as the driver is very lightweight and ++ is only in use when an administrator chooses to add an interface. ++ ++config WIREGUARD_PARALLEL ++ bool "Enable parallel engine" ++ depends on SMP && WIREGUARD ++ select PADATA ++ default y ++ ---help--- ++ This will allow WireGuard to utilize all CPU cores when encrypting ++ and decrypting packets. ++ ++ It's safe to say Y here, and you probably should, as the performance ++ improvements are substantial. ++ ++config WIREGUARD_DEBUG ++ bool "Debugging checks and verbose messages" ++ depends on WIREGUARD ++ ---help--- ++ This will write log messages for handshake and other events ++ that occur for a WireGuard interface. It will also perform some ++ extra validation checks and unit tests at various points. This is ++ only useful for debugging. ++ ++ Say N here unless you know what you're doing. +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/Makefile.include 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,11 @@ ++ccflags-y += -include $(src)/compat/compat.h ++ ++ifeq ($(wildcard $(srctree)/include/linux/siphash.h),) ++ccflags-y += -I$(src)/compat/siphash/include ++wireguard-y += compat/siphash/siphash.o ++endif ++ ++ifeq ($(wildcard $(srctree)/include/net/dst_cache.h),) ++ccflags-y += -I$(src)/compat/dst_cache/include ++wireguard-y += compat/dst_cache/dst_cache.o ++endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/compat.h 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,198 @@ ++/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ ++ ++#ifndef COMPAT_H ++#define COMPAT_H ++ ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0) ++#error "WireGuard requires Linux >= 3.18" ++#endif ++ ++/* These conditionals can't be enforced by an out of tree module very easily, ++ * so we stick them here in compat instead. */ ++#if !IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) ++#error "WireGuard requires CONFIG_NETFILTER_XT_MATCH_HASHLIMIT." ++#endif ++#if IS_ENABLED(CONFIG_IPV6) && !IS_ENABLED(CONFIG_IP6_NF_IPTABLES) ++#error "WireGuard requires CONFIG_IP6_NF_IPTABLES when using CONFIG_IPV6." ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) && !defined(DEBUG) && defined(net_dbg_ratelimited) ++#undef net_dbg_ratelimited ++#define net_dbg_ratelimited(fmt, ...) do { if (0) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#define RCU_LOCKDEP_WARN(cond, message) rcu_lockdep_assert(!(cond), message) ++#endif ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 6)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 12) ++#define dev_recursion_level() 0 ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) ++#include ++#include ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; ret__ = udp_tunnel_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, i, j, k); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#if IS_ENABLED(CONFIG_IPV6) ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb((b)->sk_socket, a, c, d, e, f, g, h, j, k); ++#endif ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0) ++#include ++#include ++static inline void fake_destructor(struct sk_buff *skb) ++{ ++} ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__; (c)->destructor = fake_destructor; (c)->sk = (b); ret__ = udp_tunnel_xmit_skb(a, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#if IS_ENABLED(CONFIG_IPV6) ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { (c)->destructor = fake_destructor; (c)->sk = (b); udp_tunnel6_xmit_skb(a, c, d, e, f, g, h, j, k, l); } while(0) ++#endif ++#else ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) ++#include ++#include ++#define udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) do { struct net_device *dev__ = (c)->dev; int ret__ = udp_tunnel_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l); iptunnel_xmit_stats(ret__, &dev__->stats, dev__->tstats); } while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0) && IS_ENABLED(CONFIG_IPV6) ++#include ++#include ++#define udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, i, j, k, l) udp_tunnel6_xmit_skb(a, b, c, d, e, f, g, h, j, k, l) ++#endif ++ ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#include ++#include ++struct udp_port_cfg_new { ++ u8 family; ++ union { ++ struct in_addr local_ip; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct in6_addr local_ip6; ++#endif ++ }; ++ union { ++ struct in_addr peer_ip; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct in6_addr peer_ip6; ++#endif ++ }; ++ __be16 local_udp_port; ++ __be16 peer_udp_port; ++ unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, use_udp6_rx_checksums:1, ipv6_v6only:1; ++}; ++static inline int __maybe_unused udp_sock_create_new(struct net *net, struct udp_port_cfg_new *cfg, struct socket **sockp) ++{ ++ struct udp_port_cfg old_cfg = { ++ .family = cfg->family, ++ .local_ip = cfg->local_ip, ++#if IS_ENABLED(CONFIG_IPV6) ++ .local_ip6 = cfg->local_ip6, ++#endif ++ .peer_ip = cfg->peer_ip, ++#if IS_ENABLED(CONFIG_IPV6) ++ .peer_ip6 = cfg->peer_ip6, ++#endif ++ .local_udp_port = cfg->local_udp_port, ++ .peer_udp_port = cfg->peer_udp_port, ++ .use_udp_checksums = cfg->use_udp_checksums, ++ .use_udp6_tx_checksums = cfg->use_udp6_tx_checksums, ++ .use_udp6_rx_checksums = cfg->use_udp6_rx_checksums ++ }; ++ if (cfg->family == AF_INET) ++ return udp_sock_create4(net, &old_cfg, sockp); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ if (cfg->family == AF_INET6) { ++ int ret; ++ int old_bindv6only; ++ struct net *nobns; ++ ++ if (cfg->ipv6_v6only) { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++ nobns = &init_net; ++#else ++ nobns = net; ++#endif ++ /* Since udp_port_cfg only learned of ipv6_v6only in 4.3, we do this horrible ++ * hack here and set the sysctl variable temporarily to something that will ++ * set the right option for us in sock_create. It's super racey! */ ++ old_bindv6only = nobns->ipv6.sysctl.bindv6only; ++ nobns->ipv6.sysctl.bindv6only = 1; ++ } ++ ret = udp_sock_create6(net, &old_cfg, sockp); ++ if (cfg->ipv6_v6only) ++ nobns->ipv6.sysctl.bindv6only = old_bindv6only; ++ return ret; ++ } ++#endif ++ return -EPFNOSUPPORT; ++} ++#define udp_port_cfg udp_port_cfg_new ++#define udp_sock_create(a, b, c) udp_sock_create_new(a, b, c) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) ++#define ipv6_dst_lookup(a, b, c, d) ipv6_dst_lookup(b, c, d) ++#endif ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 5) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 17) && LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) || LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 27) ++#define IP6_ECN_set_ce(a, b) IP6_ECN_set_ce(b) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) ++#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a) ++#define time_is_after_jiffies64(a) time_before64(get_jiffies_64(), a) ++#define time_is_before_eq_jiffies64(a) time_after_eq64(get_jiffies_64(), a) ++#define time_is_after_eq_jiffies64(a) time_before_eq64(get_jiffies_64(), a) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) && IS_ENABLED(CONFIG_IPV6) ++#include ++static inline bool ipv6_mod_enabled(void) ++{ ++ return ipv6_stub->udpv6_encap_enable != NULL; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) ++#include ++static inline void skb_reset_tc(struct sk_buff *skb) ++{ ++#ifdef CONFIG_NET_CLS_ACT ++ skb->tc_verd = 0; ++#endif ++} ++#endif ++ ++/* https://lkml.org/lkml/2015/6/12/415 */ ++#include ++static inline struct net_device *netdev_pub(void *dev) ++{ ++ return (struct net_device *)((char *)dev - ALIGN(sizeof(struct net_device), NETDEV_ALIGN)); ++} ++ ++/* PaX compatibility */ ++#ifdef CONSTIFY_PLUGIN ++#include ++#undef __read_mostly ++#define __read_mostly ++#endif ++ ++#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG) ++#define net_dbg_skb_ratelimited(fmt, skb, ...) do { \ ++ struct endpoint __endpoint; \ ++ socket_endpoint_from_skb(&__endpoint, skb); \ ++ net_dbg_ratelimited(fmt, &__endpoint.addr, ##__VA_ARGS__); \ ++} while(0) ++#else ++#define net_dbg_skb_ratelimited(fmt, skb, ...) ++#endif ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/siphash/include/linux/siphash.h 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,140 @@ ++/* Copyright (C) 2016 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This file is provided under a dual BSD/GPLv2 license. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4 for a secure PRF ++ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for ++ * hashtables. ++ */ ++ ++#ifndef _LINUX_SIPHASH_H ++#define _LINUX_SIPHASH_H ++ ++#include ++#include ++ ++#define SIPHASH_ALIGNMENT __alignof__(u64) ++typedef struct { ++ u64 key[2]; ++} siphash_key_t; ++ ++u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key); ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key); ++#endif ++ ++u64 siphash_1u64(const u64 a, const siphash_key_t *key); ++u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key); ++u64 siphash_3u64(const u64 a, const u64 b, const u64 c, ++ const siphash_key_t *key); ++u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d, ++ const siphash_key_t *key); ++u64 siphash_1u32(const u32 a, const siphash_key_t *key); ++u64 siphash_3u32(const u32 a, const u32 b, const u32 c, ++ const siphash_key_t *key); ++ ++static inline u64 siphash_2u32(const u32 a, const u32 b, ++ const siphash_key_t *key) ++{ ++ return siphash_1u64((u64)b << 32 | a, key); ++} ++static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c, ++ const u32 d, const siphash_key_t *key) ++{ ++ return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key); ++} ++ ++ ++static inline u64 ___siphash_aligned(const __le64 *data, size_t len, ++ const siphash_key_t *key) ++{ ++ if (__builtin_constant_p(len) && len == 4) ++ return siphash_1u32(le32_to_cpup((const __le32 *)data), key); ++ if (__builtin_constant_p(len) && len == 8) ++ return siphash_1u64(le64_to_cpu(data[0]), key); ++ if (__builtin_constant_p(len) && len == 16) ++ return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ key); ++ if (__builtin_constant_p(len) && len == 24) ++ return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ le64_to_cpu(data[2]), key); ++ if (__builtin_constant_p(len) && len == 32) ++ return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]), ++ le64_to_cpu(data[2]), le64_to_cpu(data[3]), ++ key); ++ return __siphash_aligned(data, len, key); ++} ++ ++/** ++ * siphash - compute 64-bit siphash PRF value ++ * @data: buffer to hash ++ * @size: size of @data ++ * @key: the siphash key ++ */ ++static inline u64 siphash(const void *data, size_t len, ++ const siphash_key_t *key) ++{ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (!IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT)) ++ return __siphash_unaligned(data, len, key); ++#endif ++ return ___siphash_aligned(data, len, key); ++} ++ ++#define HSIPHASH_ALIGNMENT __alignof__(unsigned long) ++typedef struct { ++ unsigned long key[2]; ++} hsiphash_key_t; ++ ++u32 __hsiphash_aligned(const void *data, size_t len, ++ const hsiphash_key_t *key); ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key); ++#endif ++ ++u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key); ++u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key); ++u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c, ++ const hsiphash_key_t *key); ++u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d, ++ const hsiphash_key_t *key); ++ ++static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ if (__builtin_constant_p(len) && len == 4) ++ return hsiphash_1u32(le32_to_cpu(data[0]), key); ++ if (__builtin_constant_p(len) && len == 8) ++ return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ key); ++ if (__builtin_constant_p(len) && len == 12) ++ return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ le32_to_cpu(data[2]), key); ++ if (__builtin_constant_p(len) && len == 16) ++ return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]), ++ le32_to_cpu(data[2]), le32_to_cpu(data[3]), ++ key); ++ return __hsiphash_aligned(data, len, key); ++} ++ ++/** ++ * hsiphash - compute 32-bit hsiphash PRF value ++ * @data: buffer to hash ++ * @size: size of @data ++ * @key: the hsiphash key ++ */ ++static inline u32 hsiphash(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++ if (!IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT)) ++ return __hsiphash_unaligned(data, len, key); ++#endif ++ return ___hsiphash_aligned(data, len, key); ++} ++ ++#endif /* _LINUX_SIPHASH_H */ +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/siphash/siphash.c 2017-03-05 17:03:41.525682403 +0200 +@@ -0,0 +1,551 @@ ++/* Copyright (C) 2016 Jason A. Donenfeld . All Rights Reserved. ++ * ++ * This file is provided under a dual BSD/GPLv2 license. ++ * ++ * SipHash: a fast short-input PRF ++ * https://131002.net/siphash/ ++ * ++ * This implementation is specifically for SipHash2-4 for a secure PRF ++ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for ++ * hashtables. ++ */ ++ ++#include ++#include ++ ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++#include ++#include ++#endif ++ ++#define SIPROUND \ ++ do { \ ++ v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \ ++ v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \ ++ v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \ ++ v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \ ++ } while (0) ++ ++#define PREAMBLE(len) \ ++ u64 v0 = 0x736f6d6570736575ULL; \ ++ u64 v1 = 0x646f72616e646f6dULL; \ ++ u64 v2 = 0x6c7967656e657261ULL; \ ++ u64 v3 = 0x7465646279746573ULL; \ ++ u64 b = ((u64)(len)) << 56; \ ++ v3 ^= key->key[1]; \ ++ v2 ^= key->key[0]; \ ++ v1 ^= key->key[1]; \ ++ v0 ^= key->key[0]; ++ ++#define POSTAMBLE \ ++ v3 ^= b; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ SIPROUND; \ ++ return (v0 ^ v1) ^ (v2 ^ v3); ++ ++u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ PREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = le64_to_cpup(data); ++ v3 ^= m; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= le32_to_cpup(data); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ POSTAMBLE ++} ++EXPORT_SYMBOL(__siphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ PREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = get_unaligned_le64(data); ++ v3 ^= m; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= get_unaligned_le32(end); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ POSTAMBLE ++} ++EXPORT_SYMBOL(__siphash_unaligned); ++#endif ++ ++/** ++ * siphash_1u64 - compute 64-bit siphash PRF value of a u64 ++ * @first: first u64 ++ * @key: the siphash key ++ */ ++u64 siphash_1u64(const u64 first, const siphash_key_t *key) ++{ ++ PREAMBLE(8) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_1u64); ++ ++/** ++ * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @key: the siphash key ++ */ ++u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key) ++{ ++ PREAMBLE(16) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_2u64); ++ ++/** ++ * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @third: third u64 ++ * @key: the siphash key ++ */ ++u64 siphash_3u64(const u64 first, const u64 second, const u64 third, ++ const siphash_key_t *key) ++{ ++ PREAMBLE(24) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= third; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_3u64); ++ ++/** ++ * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64 ++ * @first: first u64 ++ * @second: second u64 ++ * @third: third u64 ++ * @forth: forth u64 ++ * @key: the siphash key ++ */ ++u64 siphash_4u64(const u64 first, const u64 second, const u64 third, ++ const u64 forth, const siphash_key_t *key) ++{ ++ PREAMBLE(32) ++ v3 ^= first; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= third; ++ v3 ^= forth; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= forth; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_4u64); ++ ++u64 siphash_1u32(const u32 first, const siphash_key_t *key) ++{ ++ PREAMBLE(4) ++ b |= first; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_1u32); ++ ++u64 siphash_3u32(const u32 first, const u32 second, const u32 third, ++ const siphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ PREAMBLE(12) ++ v3 ^= combined; ++ SIPROUND; ++ SIPROUND; ++ v0 ^= combined; ++ b |= third; ++ POSTAMBLE ++} ++EXPORT_SYMBOL(siphash_3u32); ++ ++#if BITS_PER_LONG == 64 ++/* Note that on 64-bit, we make HalfSipHash1-3 actually be SipHash1-3, for ++ * performance reasons. On 32-bit, below, we actually implement HalfSipHash1-3. ++ */ ++ ++#define HSIPROUND SIPROUND ++#define HPREAMBLE(len) PREAMBLE(len) ++#define HPOSTAMBLE \ ++ v3 ^= b; \ ++ HSIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ return (v0 ^ v1) ^ (v2 ^ v3); ++ ++u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = le64_to_cpup(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= le32_to_cpup(data); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u64)); ++ const u8 left = len & (sizeof(u64) - 1); ++ u64 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u64)) { ++ m = get_unaligned_le64(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64 ++ if (left) ++ b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) & ++ bytemask_from_count(left))); ++#else ++ switch (left) { ++ case 7: b |= ((u64)end[6]) << 48; ++ case 6: b |= ((u64)end[5]) << 40; ++ case 5: b |= ((u64)end[4]) << 32; ++ case 4: b |= get_unaligned_le32(end); break; ++ case 3: b |= ((u64)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++#endif ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_unaligned); ++#endif ++ ++/** ++ * hsiphash_1u32 - compute 64-bit hsiphash PRF value of a u32 ++ * @first: first u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(4) ++ b |= first; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_1u32); ++ ++/** ++ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(8) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_2u32); ++ ++/** ++ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third, ++ const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(12) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ b |= third; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_3u32); ++ ++/** ++ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @forth: forth u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third, ++ const u32 forth, const hsiphash_key_t *key) ++{ ++ u64 combined = (u64)second << 32 | first; ++ HPREAMBLE(16) ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ combined = (u64)forth << 32 | third; ++ v3 ^= combined; ++ HSIPROUND; ++ v0 ^= combined; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_4u32); ++#else ++#define HSIPROUND \ ++ do { \ ++ v0 += v1; v1 = rol32(v1, 5); v1 ^= v0; v0 = rol32(v0, 16); \ ++ v2 += v3; v3 = rol32(v3, 8); v3 ^= v2; \ ++ v0 += v3; v3 = rol32(v3, 7); v3 ^= v0; \ ++ v2 += v1; v1 = rol32(v1, 13); v1 ^= v2; v2 = rol32(v2, 16); \ ++ } while (0) ++ ++#define HPREAMBLE(len) \ ++ u32 v0 = 0; \ ++ u32 v1 = 0; \ ++ u32 v2 = 0x6c796765U; \ ++ u32 v3 = 0x74656462U; \ ++ u32 b = ((u32)(len)) << 24; \ ++ v3 ^= key->key[1]; \ ++ v2 ^= key->key[0]; \ ++ v1 ^= key->key[1]; \ ++ v0 ^= key->key[0]; ++ ++#define HPOSTAMBLE \ ++ v3 ^= b; \ ++ HSIPROUND; \ ++ v0 ^= b; \ ++ v2 ^= 0xff; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ HSIPROUND; \ ++ return v1 ^ v3; ++ ++u32 __hsiphash_aligned(const void *data, size_t len, const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u32)); ++ const u8 left = len & (sizeof(u32) - 1); ++ u32 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u32)) { ++ m = le32_to_cpup(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++ switch (left) { ++ case 3: b |= ((u32)end[2]) << 16; ++ case 2: b |= le16_to_cpup(data); break; ++ case 1: b |= end[0]; ++ } ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_aligned); ++ ++#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS ++u32 __hsiphash_unaligned(const void *data, size_t len, ++ const hsiphash_key_t *key) ++{ ++ const u8 *end = data + len - (len % sizeof(u32)); ++ const u8 left = len & (sizeof(u32) - 1); ++ u32 m; ++ HPREAMBLE(len) ++ for (; data != end; data += sizeof(u32)) { ++ m = get_unaligned_le32(data); ++ v3 ^= m; ++ HSIPROUND; ++ v0 ^= m; ++ } ++ switch (left) { ++ case 3: b |= ((u32)end[2]) << 16; ++ case 2: b |= get_unaligned_le16(end); break; ++ case 1: b |= end[0]; ++ } ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(__hsiphash_unaligned); ++#endif ++ ++/** ++ * hsiphash_1u32 - compute 32-bit hsiphash PRF value of a u32 ++ * @first: first u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_1u32(const u32 first, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(4) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_1u32); ++ ++/** ++ * hsiphash_2u32 - compute 32-bit hsiphash PRF value of 2 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_2u32(const u32 first, const u32 second, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(8) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_2u32); ++ ++/** ++ * hsiphash_3u32 - compute 32-bit hsiphash PRF value of 3 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_3u32(const u32 first, const u32 second, const u32 third, ++ const hsiphash_key_t *key) ++{ ++ HPREAMBLE(12) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ HSIPROUND; ++ v0 ^= third; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_3u32); ++ ++/** ++ * hsiphash_4u32 - compute 32-bit hsiphash PRF value of 4 u32 ++ * @first: first u32 ++ * @second: second u32 ++ * @third: third u32 ++ * @forth: forth u32 ++ * @key: the hsiphash key ++ */ ++u32 hsiphash_4u32(const u32 first, const u32 second, const u32 third, ++ const u32 forth, const hsiphash_key_t *key) ++{ ++ HPREAMBLE(16) ++ v3 ^= first; ++ HSIPROUND; ++ v0 ^= first; ++ v3 ^= second; ++ HSIPROUND; ++ v0 ^= second; ++ v3 ^= third; ++ HSIPROUND; ++ v0 ^= third; ++ v3 ^= forth; ++ HSIPROUND; ++ v0 ^= forth; ++ HPOSTAMBLE ++} ++EXPORT_SYMBOL(hsiphash_4u32); ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/dst_cache/include/net/dst_cache.h 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,97 @@ ++#ifndef _NET_DST_CACHE_H ++#define _NET_DST_CACHE_H ++ ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#endif ++ ++struct dst_cache { ++ struct dst_cache_pcpu __percpu *cache; ++ unsigned long reset_ts; ++}; ++ ++/** ++ * dst_cache_get - perform cache lookup ++ * @dst_cache: the cache ++ * ++ * The caller should use dst_cache_get_ip4() if it need to retrieve the ++ * source address to be used when xmitting to the cached dst. ++ * local BH must be disabled. ++ */ ++struct dst_entry *dst_cache_get(struct dst_cache *dst_cache); ++ ++/** ++ * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address ++ * @dst_cache: the cache ++ * @saddr: return value for the retrieved source address ++ * ++ * local BH must be disabled. ++ */ ++struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr); ++ ++/** ++ * dst_cache_set_ip4 - store the ipv4 dst into the cache ++ * @dst_cache: the cache ++ * @dst: the entry to be cached ++ * @saddr: the source address to be stored inside the cache ++ * ++ * local BH must be disabled. ++ */ ++void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, ++ __be32 saddr); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++ ++/** ++ * dst_cache_set_ip6 - store the ipv6 dst into the cache ++ * @dst_cache: the cache ++ * @dst: the entry to be cached ++ * @saddr: the source address to be stored inside the cache ++ * ++ * local BH must be disabled. ++ */ ++void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, ++ const struct in6_addr *addr); ++ ++/** ++ * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address ++ * @dst_cache: the cache ++ * @saddr: return value for the retrieved source address ++ * ++ * local BH must be disabled. ++ */ ++struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, ++ struct in6_addr *saddr); ++#endif ++ ++/** ++ * dst_cache_reset - invalidate the cache contents ++ * @dst_cache: the cache ++ * ++ * This do not free the cached dst to avoid races and contentions. ++ * the dst will be freed on later cache lookup. ++ */ ++static inline void dst_cache_reset(struct dst_cache *dst_cache) ++{ ++ dst_cache->reset_ts = jiffies; ++} ++ ++/** ++ * dst_cache_init - initialize the cache, allocating the required storage ++ * @dst_cache: the cache ++ * @gfp: allocation flags ++ */ ++int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp); ++ ++/** ++ * dst_cache_destroy - empty the cache and free the allocated storage ++ * @dst_cache: the cache ++ * ++ * No synchronization is enforced: it must be called only when the cache ++ * is unsed. ++ */ ++void dst_cache_destroy(struct dst_cache *dst_cache); ++ ++#endif +--- /dev/null 2017-03-05 14:08:30.231833430 +0200 ++++ b/net/wireguard/compat/dst_cache/dst_cache.c 2017-03-05 17:03:41.524682397 +0200 +@@ -0,0 +1,177 @@ ++/* ++ * net/core/dst_cache.c - dst entry cache ++ * ++ * Copyright (c) 2016 Paolo Abeni ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#if IS_ENABLED(CONFIG_IPV6) ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) ++static inline u32 rt6_get_cookie(const struct rt6_info *rt) ++{ ++ if ((unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from)) ++ rt = (struct rt6_info *)(rt->dst.from); ++ ++ return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; ++} ++#endif ++#endif ++#include ++ ++struct dst_cache_pcpu { ++ unsigned long refresh_ts; ++ struct dst_entry *dst; ++ u32 cookie; ++ union { ++ struct in_addr in_saddr; ++ struct in6_addr in6_saddr; ++ }; ++}; ++ ++static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache, ++ struct dst_entry *dst, u32 cookie) ++{ ++ dst_release(dst_cache->dst); ++ if (dst) ++ dst_hold(dst); ++ ++ dst_cache->cookie = cookie; ++ dst_cache->dst = dst; ++} ++ ++static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache, ++ struct dst_cache_pcpu *idst) ++{ ++ struct dst_entry *dst; ++ ++ dst = idst->dst; ++ if (!dst) ++ goto fail; ++ ++ /* the cache already hold a dst reference; it can't go away */ ++ dst_hold(dst); ++ ++ if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) || ++ (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) { ++ dst_cache_per_cpu_dst_set(idst, NULL, 0); ++ dst_release(dst); ++ goto fail; ++ } ++ return dst; ++ ++fail: ++ idst->refresh_ts = jiffies; ++ return NULL; ++} ++ ++struct dst_entry *dst_cache_get(struct dst_cache *dst_cache) ++{ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache)); ++} ++EXPORT_SYMBOL_GPL(dst_cache_get); ++ ++struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ struct dst_entry *dst; ++ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst = dst_cache_per_cpu_get(dst_cache, idst); ++ if (!dst) ++ return NULL; ++ ++ *saddr = idst->in_saddr.s_addr; ++ return container_of(dst, struct rtable, dst); ++} ++EXPORT_SYMBOL_GPL(dst_cache_get_ip4); ++ ++void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, ++ __be32 saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst_cache_per_cpu_dst_set(idst, dst, 0); ++ idst->in_saddr.s_addr = saddr; ++} ++EXPORT_SYMBOL_GPL(dst_cache_set_ip4); ++ ++#if IS_ENABLED(CONFIG_IPV6) ++void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, ++ const struct in6_addr *addr) ++{ ++ struct dst_cache_pcpu *idst; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst, ++ rt6_get_cookie((struct rt6_info *)dst)); ++ idst->in6_saddr = *addr; ++} ++EXPORT_SYMBOL_GPL(dst_cache_set_ip6); ++ ++struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, ++ struct in6_addr *saddr) ++{ ++ struct dst_cache_pcpu *idst; ++ struct dst_entry *dst; ++ ++ if (!dst_cache->cache) ++ return NULL; ++ ++ idst = this_cpu_ptr(dst_cache->cache); ++ dst = dst_cache_per_cpu_get(dst_cache, idst); ++ if (!dst) ++ return NULL; ++ ++ *saddr = idst->in6_saddr; ++ return dst; ++} ++EXPORT_SYMBOL_GPL(dst_cache_get_ip6); ++#endif ++ ++int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp) ++{ ++ dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu, ++ gfp | __GFP_ZERO); ++ if (!dst_cache->cache) ++ return -ENOMEM; ++ ++ dst_cache_reset(dst_cache); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(dst_cache_init); ++ ++void dst_cache_destroy(struct dst_cache *dst_cache) ++{ ++ int i; ++ ++ if (!dst_cache->cache) ++ return; ++ ++ for_each_possible_cpu(i) ++ dst_release(per_cpu_ptr(dst_cache->cache, i)->dst); ++ ++ free_percpu(dst_cache->cache); ++} ++EXPORT_SYMBOL_GPL(dst_cache_destroy); +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -85,2 +85,3 @@ config INET + if INET ++source "net/wireguard/Kconfig" + source "net/ipv4/Kconfig" +--- a/net/Makefile ++++ b/net/Makefile +@@ -16,2 +16,3 @@ + obj-$(CONFIG_NETFILTER) += netfilter/ ++obj-$(CONFIG_WIREGUARD) += wireguard/ + obj-$(CONFIG_INET) += ipv4/ diff --git a/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch b/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch deleted file mode 100644 index cee31761..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch +++ /dev/null @@ -1,29 +0,0 @@ - -From: Gavin Li - -brcmf_sdio_fromevntchan() was being called on the the data frame -rather than the software header, causing some frames to be -mischaracterized as on the event channel rather than the data channel. - -This fixes a major performance regression (due to dropped packets). - -Fixes: c56caa9db8ab ("brcmfmac: screening firmware event packet") -Signed-off-by: Gavin Li -Cc: [4.7+] ---- - drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -index dfb0658713d9..d2219885071f 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -1661,7 +1661,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) - pfirst->len, pfirst->next, - pfirst->prev); - skb_unlink(pfirst, &bus->glom); -- if (brcmf_sdio_fromevntchan(pfirst->data)) -+ if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN])) - brcmf_rx_event(bus->sdiodev->dev, pfirst); - else - brcmf_rx_frame(bus->sdiodev->dev, pfirst, diff --git a/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch b/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch new file mode 100644 index 00000000..6f7092cc --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch @@ -0,0 +1,371 @@ + +From upstream 4.11-rc2+ git + +Fixes mga #20508 + +Signed-off-by: Thomas Backlund + + + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 29 ++-- + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 4 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_872tb.c | 2 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 121 +++++++++++------ + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h | 2 + 7 files changed, 105 insertions(+), 57 deletions(-) + +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c 2017-03-07 22:29:07.840867965 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8188c/8188r/8192c specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8192e specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +@@ -1556,7 +1556,7 @@ exit: + return ret; + } + +-void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) ++static void rtl8192eu_power_off(struct rtl8xxxu_priv *priv) + { + u8 val8; + u16 val16; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8723a specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver - 8723b specific subdriver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c 2017-03-18 13:35:47.148080457 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c 2017-03-07 22:29:07.841868054 +0200 +@@ -1,7 +1,7 @@ + /* + * RTL8XXXU mac80211 USB driver + * +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * Portions, notably calibration code: + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +@@ -48,7 +48,7 @@ static bool rtl8xxxu_dma_aggregation; + static int rtl8xxxu_dma_agg_timeout = -1; + static int rtl8xxxu_dma_agg_pages = -1; + +-MODULE_AUTHOR("Jes Sorensen "); ++MODULE_AUTHOR("Jes Sorensen "); + MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver"); + MODULE_LICENSE("GPL"); + MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin"); +@@ -4767,13 +4767,28 @@ static void rtl8xxxu_dump_action(struct + * This format is used on 8188cu/8192cu/8723au + */ + void +-rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable) ++rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, u32 rts_rate) + { ++ struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); ++ struct rtl8xxxu_priv *priv = hw->priv; ++ struct device *dev = &priv->udev->dev; ++ u32 rate; ++ u16 rate_flags = tx_info->control.rates[0].flags; + u16 seq_number; + ++ if (rate_flags & IEEE80211_TX_RC_MCS && ++ !ieee80211_is_mgmt(hdr->frame_control)) ++ rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; ++ else ++ rate = tx_rate->hw_value; ++ ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) ++ dev_info(dev, "%s: TX rate: %d, pkt size %d\n", ++ __func__, rate, cpu_to_le16(tx_desc->pkt_size)); ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + tx_desc->txdw5 = cpu_to_le32(rate); +@@ -4804,15 +4819,16 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211 + if (sgi) + tx_desc->txdw5 |= cpu_to_le32(TXDESC32_SHORT_GI); + +- if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { +- /* +- * Use RTS rate 24M - does the mac80211 tell +- * us which to use? +- */ +- tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M << +- TXDESC32_RTS_RATE_SHIFT); ++ /* ++ * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled ++ */ ++ tx_desc->txdw4 |= cpu_to_le32(rts_rate << TXDESC32_RTS_RATE_SHIFT); ++ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_RTS_CTS_ENABLE); + tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); ++ } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ++ tx_desc->txdw4 |= cpu_to_le32(TXDESC32_CTS_SELF_ENABLE); ++ tx_desc->txdw4 |= cpu_to_le32(TXDESC32_HW_RTS_ENABLE); + } + } + +@@ -4821,16 +4837,31 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211 + * This format is used on 8192eu/8723bu + */ + void +-rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable) ++rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, ++ bool short_preamble, bool ampdu_enable, u32 rts_rate) + { ++ struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); ++ struct rtl8xxxu_priv *priv = hw->priv; ++ struct device *dev = &priv->udev->dev; + struct rtl8xxxu_txdesc40 *tx_desc40; ++ u32 rate; ++ u16 rate_flags = tx_info->control.rates[0].flags; + u16 seq_number; + + tx_desc40 = (struct rtl8xxxu_txdesc40 *)tx_desc32; + ++ if (rate_flags & IEEE80211_TX_RC_MCS && ++ !ieee80211_is_mgmt(hdr->frame_control)) ++ rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; ++ else ++ rate = tx_rate->hw_value; ++ ++ if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) ++ dev_info(dev, "%s: TX rate: %d, pkt size %d\n", ++ __func__, rate, cpu_to_le16(tx_desc40->pkt_size)); ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + + tx_desc40->txdw4 = cpu_to_le32(rate); +@@ -4857,15 +4888,19 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211 + if (short_preamble) + tx_desc40->txdw5 |= cpu_to_le32(TXDESC40_SHORT_PREAMBLE); + +- if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) { +- /* +- * Use RTS rate 24M - does the mac80211 tell +- * us which to use? +- */ +- tx_desc40->txdw4 |= cpu_to_le32(DESC_RATE_24M << +- TXDESC40_RTS_RATE_SHIFT); ++ tx_desc40->txdw4 |= cpu_to_le32(rts_rate << TXDESC40_RTS_RATE_SHIFT); ++ /* ++ * rts_rate is zero if RTS/CTS or CTS to SELF are not enabled ++ */ ++ if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { + tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_RTS_CTS_ENABLE); + tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_HW_RTS_ENABLE); ++ } else if (rate_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ++ /* ++ * For some reason the vendor driver doesn't set ++ * TXDESC40_HW_RTS_ENABLE for CTS to SELF ++ */ ++ tx_desc40->txdw3 |= cpu_to_le32(TXDESC40_CTS_SELF_ENABLE); + } + } + +@@ -4875,14 +4910,13 @@ static void rtl8xxxu_tx(struct ieee80211 + { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); +- struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info); + struct rtl8xxxu_priv *priv = hw->priv; + struct rtl8xxxu_txdesc32 *tx_desc; + struct rtl8xxxu_tx_urb *tx_urb; + struct ieee80211_sta *sta = NULL; + struct ieee80211_vif *vif = tx_info->control.vif; + struct device *dev = &priv->udev->dev; +- u32 queue, rate; ++ u32 queue, rts_rate; + u16 pktlen = skb->len; + u16 seq_number; + u16 rate_flag = tx_info->control.rates[0].flags; +@@ -4909,10 +4943,6 @@ static void rtl8xxxu_tx(struct ieee80211 + goto error; + } + +- if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX) +- dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n", +- __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen); +- + if (ieee80211_is_action(hdr->frame_control)) + rtl8xxxu_dump_action(dev, hdr); + +@@ -4966,12 +4996,6 @@ static void rtl8xxxu_tx(struct ieee80211 + } + } + +- if (rate_flag & IEEE80211_TX_RC_MCS && +- !ieee80211_is_mgmt(hdr->frame_control)) +- rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0; +- else +- rate = tx_rate->hw_value; +- + if (rate_flag & IEEE80211_TX_RC_SHORT_GI || + (ieee80211_is_data_qos(hdr->frame_control) && + sta && sta->ht_cap.cap & +@@ -4982,10 +5006,17 @@ static void rtl8xxxu_tx(struct ieee80211 + (sta && vif && vif->bss_conf.use_short_preamble)) + short_preamble = true; + ++ if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) ++ rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; ++ else if (rate_flag & IEEE80211_TX_RC_USE_CTS_PROTECT) ++ rts_rate = ieee80211_get_rts_cts_rate(hw, tx_info)->hw_value; ++ else ++ rts_rate = 0; ++ + seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + +- priv->fops->fill_txdesc(hdr, tx_desc, rate, rate_flag, +- sgi, short_preamble, ampdu_enable); ++ priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, ++ ampdu_enable, rts_rate); + + rtl8xxxu_calc_tx_desc_csum(tx_desc); + +@@ -5969,6 +6000,7 @@ static int rtl8xxxu_probe(struct usb_int + case 0x8176: + case 0x8178: + case 0x817f: ++ case 0x818b: + untested = 0; + break; + } +@@ -6165,6 +6197,12 @@ static struct usb_device_id dev_table[] + .driver_info = (unsigned long)&rtl8723au_fops}, + {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818b, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192eu_fops}, ++/* TP-Link TL-WN822N v4 */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0108, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++/* D-Link DWA-131 rev E1, tested by David Patiño */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3319, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, + /* Tested by Myckel Habets */ + {USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0109, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192eu_fops}, +@@ -6316,6 +6354,13 @@ static struct usb_device_id dev_table[] + .driver_info = (unsigned long)&rtl8192cu_fops}, + {USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8192cu_fops}, ++/* found in rtl8192eu vendor driver */ ++{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0107, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab33, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, ++{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818c, 0xff, 0xff, 0xff), ++ .driver_info = (unsigned long)&rtl8192eu_fops}, + #endif + { } + }; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h 2017-03-07 22:29:07.840867965 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as +@@ -1337,10 +1337,11 @@ struct rtl8xxxu_fileops { + u32 ramask, int sgi); + void (*report_connect) (struct rtl8xxxu_priv *priv, + u8 macid, bool connect); +- void (*fill_txdesc) (struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); ++ void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); + int writeN_block_size; + int rx_agg_buf_size; + char tx_desc_size; +@@ -1434,14 +1435,16 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8x + int rtl8xxxu_gen2_channel_to_group(int channel); + bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv, + int result[][8], int c1, int c2); +-void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); +-void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hdr *hdr, +- struct rtl8xxxu_txdesc32 *tx_desc32, u32 rate, +- u16 rate_flag, bool sgi, bool short_preamble, +- bool ampdu_enable); ++void rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); ++void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, ++ struct ieee80211_tx_info *tx_info, ++ struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, ++ bool short_preamble, bool ampdu_enable, ++ u32 rts_rate); + + extern struct rtl8xxxu_fileops rtl8192cu_fops; + extern struct rtl8xxxu_fileops rtl8192eu_fops; +diff -Nurp linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +--- linux-4.9.16/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h 2016-12-11 21:17:54.000000000 +0200 ++++ linux-4.11-rc/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h 2017-03-07 22:29:07.842868144 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2014 - 2016 Jes Sorensen ++ * Copyright (c) 2014 - 2017 Jes Sorensen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as diff --git a/kernel/tools/cpupowertools/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch b/kernel/tools/cpupowertools/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch new file mode 100644 index 00000000..0383b3ba --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch @@ -0,0 +1,43 @@ +From: Joerg Roedel + +ATS is broken on these devices. Under invalidation load, the +GPU does not reply to invalidations anymore, causing +Completion-wait loop timeouts on the AMD IOMMU driver side. +Fix it by not enabling ATS on these devices. + +Note that below mentioned commit is not broken, it just +triggers the issue because it might cause invalidation +storms on devices. + +Fixes: b1516a14657a ('iommu/amd: Implement flush queue') +Reported-by: Daniel Drake +Cc: Daniel Drake +Cc: Alexander Deucher +Signed-off-by: Joerg Roedel +--- + drivers/pci/ats.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c +index eeb9fb2..711bdb2 100644 +--- a/drivers/pci/ats.c ++++ b/drivers/pci/ats.c +@@ -17,10 +17,18 @@ + + #include "pci.h" + ++static const struct pci_device_id broken_ats_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x98e4) }, /* AMD Stoney GPU part */ ++ { 0 } ++}; ++ + void pci_ats_init(struct pci_dev *dev) + { + int pos; + ++ if (pci_match_id(broken_ats_tbl, dev)) ++ return; ++ + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); + if (!pos) + return; diff --git a/kernel/tools/cpupowertools/files/patches/mageia/series b/kernel/tools/cpupowertools/files/patches/mageia/series index ca9b5050..92c06398 100644 --- a/kernel/tools/cpupowertools/files/patches/mageia/series +++ b/kernel/tools/cpupowertools/files/patches/mageia/series @@ -14,14 +14,7 @@ ### ### Stable Queue ### - -# CVE-2016-8405 -stable-fbdev-color-map-copying-bounds-checking.patch - -stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch -stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch -stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch -stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch +patch-4.9.19-rc1.patch ### ### Arch x86 @@ -46,9 +39,6 @@ x86-increase-default-minimum-vmalloc-area-by-64MB-to-192MB.patch # slows down boot Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch -# breaks nvidia304 -Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch - ### ### Core ### @@ -68,6 +58,9 @@ base-cacheinfo-silence-DT-warnings.patch pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch pci-quirks-drop-devinit-exit.patch +# Stoney iommu hang +pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch + ### ### PNP core ### @@ -88,6 +81,9 @@ ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch # drop obsolete warn acpi-do-not-warn-if-_BQC-does-not-exist.patch +# silence useless acpi warnings +acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch + ### ### Block ### @@ -137,6 +133,9 @@ block-introduce-the-BFQ-v7r11-I-O-sched-for-4.5.0.patch block-bfq-add-Early-Queue-Merge-EQM-to-BFQ-v7r11-for.patch block-Turn-into-BFQ-v8r6-for-4.9.0.patch +# new macbooks +block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch + ### ### Char ### @@ -194,11 +193,16 @@ gpu-drm-mach64-linux-3.14-buildfix.patch gpu-drm-mach64-3.17-buildfix.patch gpu-drm-mach64-3.18-buildfix.patch -# i915 skl/kbl speedup -gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch -gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch -gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch -gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch +# +gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch + +# Amd polaris12 support +gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch +gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch +gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch + +# fix crash +gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch ### ### Hardware Monitoring @@ -256,8 +260,11 @@ net-netfilter-psd-fix-redefines.patch net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch -# fix speed regression -net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch +# update rtl8xxxu for mga#20508 +net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch + +# WireGuard support +net-wireguard.patch ### ### Platform drivers @@ -284,6 +291,10 @@ include-kbuild-export-pci_ids.patch ### Sound ### +# new codecs +sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch +sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch + ### ### Staging ### diff --git a/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch b/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch new file mode 100644 index 00000000..ae18a31b --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch @@ -0,0 +1,102 @@ +From 28f1f9b26cee161ddd3985b3eb78e3ffada08dda Mon Sep 17 00:00:00 2001 +From: Kailang Yang +Date: Wed, 4 Jan 2017 14:49:07 +0800 +Subject: [PATCH] ALSA: hda/realtek - Add new codec ID ALC299 + +ALC299 was similar as ALC225. +Add headset support for ALC299. +ALC3271 was for Dell rename. + +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_realtek.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 1ae29fd..3c69647 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + case 0x10ec0288: + case 0x10ec0295: + case 0x10ec0298: ++ case 0x10ec0299: + alc_update_coef_idx(codec, 0x10, 1<<9, 0); + break; + case 0x10ec0285: +@@ -912,6 +913,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { + { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, + { 0x10ec0295, 0x1028, 0, "ALC3254" }, ++ { 0x10ec0299, 0x1028, 0, "ALC3271" }, + { 0x10ec0670, 0x1025, 0, "ALC669X" }, + { 0x10ec0676, 0x1025, 0, "ALC679X" }, + { 0x10ec0282, 0x1043, 0, "ALC3229" }, +@@ -3716,6 +3718,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0867: +@@ -3823,6 +3826,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_process_coef_fw(codec, coef0225); +@@ -3881,6 +3885,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) + switch (codec->core.vendor_id) { + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0255: +@@ -3996,6 +4001,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + case 0x10ec0867: +@@ -4089,6 +4095,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + break; + } +@@ -4173,6 +4180,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + alc_process_coef_fw(codec, coef0225); + msleep(800); + val = alc_read_coef_idx(codec, 0x46); +@@ -6219,6 +6227,7 @@ static int patch_alc269(struct hda_codec *codec) + break; + case 0x10ec0225: + case 0x10ec0295: ++ case 0x10ec0299: + spec->codec_variant = ALC269_TYPE_ALC225; + break; + case 0x10ec0234: +@@ -7256,6 +7265,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), ++ HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269), + HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), + HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), + HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861), +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch b/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch new file mode 100644 index 00000000..70646467 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch @@ -0,0 +1,45 @@ +From a535ad57d0e6b959cd79914a1127caade36a9459 Mon Sep 17 00:00:00 2001 +From: Kailang Yang +Date: Mon, 16 Jan 2017 16:59:26 +0800 +Subject: [PATCH] ALSA: hda/realtek - New codec support of ALC1220 + +Add support for new codec of ALC1220. +It's compatible with ALC882 & co. + +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +--- + sound/pci/hda/patch_realtek.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 3c69647..1c88da8 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -380,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) + break; + case 0x10ec0899: + case 0x10ec0900: ++ case 0x10ec1220: + alc_update_coef_idx(codec, 0x7, 1<<1, 0); + break; + } +@@ -2310,6 +2311,7 @@ static int patch_alc882(struct hda_codec *codec) + case 0x10ec0882: + case 0x10ec0885: + case 0x10ec0900: ++ case 0x10ec1220: + break; + default: + /* ALC883 and variants */ +@@ -7297,6 +7299,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { + HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), + HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), ++ HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), + {} /* terminator */ + }; + MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); +-- +2.10.2 + diff --git a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch b/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch deleted file mode 100644 index 1e434efd..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch +++ /dev/null @@ -1,71 +0,0 @@ -From fdf35a6b22247746a7053fc764d04218a9306f82 Mon Sep 17 00:00:00 2001 -From: Takashi Iwai -Date: Mon, 9 Jan 2017 15:56:14 +0100 -Subject: drm: Fix broken VT switch with video=1366x768 option -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -From: Takashi Iwai - -commit fdf35a6b22247746a7053fc764d04218a9306f82 upstream. - -I noticed that the VT switch doesn't work any longer with a Dell -laptop with 1366x768 eDP when the machine is connected with a DP -monitor. It behaves as if VT were switched, but the graphics remain -frozen. Actually the keyboard works, so I could switch back to VT7 -again. - -I tried to track down the problem, and encountered a long story until -we reach to this error: - -- The machine is booted with video=1366x768 option (the distro - installer seems to add it as default). -- Recently, drm_helper_probe_single_connector_modes() deals with - cmdline modes, and it tries to create a new mode when no - matching mode is found. -- The drm_mode_create_from_cmdline_mode() creates a mode based on - either CVT of GFT according to the given cmdline mode; in our case, - it's 1366x768. -- Since both CVT and GFT can't express the width 1366 due to - alignment, the resultant mode becomes 1368x768, slightly larger than - the given size. -- Later on, the atomic commit is performed, and in - drm_atomic_check_only(), the size of each plane is checked. -- The size check of 1366x768 fails due to the above, and eventually - the whole VT switch fails. - -Back in the history, we've had a manual fix-up of 1368x768 in various -places via c09dedb7a50e ("drm/edid: Add a workaround for 1366x768 HD -panel"), but they have been all in drm_edid.c at probing the modes -from EDID. For addressing the problem above, we need a similar hack -to the mode newly created from cmdline, manually adjusting the width -when the expected size is 1366 while we get 1368 instead. - -Fixes: eaf99c749d43 ("drm: Perform cmdline mode parsing during...") -Signed-off-by: Takashi Iwai -Link: http://patchwork.freedesktop.org/patch/msgid/20170109145614.29454-1-tiwai@suse.de -Reviewed-by: Ville Syrjälä -Signed-off-by: Ville Syrjälä -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/drm_modes.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/gpu/drm/drm_modes.c -+++ b/drivers/gpu/drm/drm_modes.c -@@ -1462,6 +1462,13 @@ drm_mode_create_from_cmdline_mode(struct - return NULL; - - mode->type |= DRM_MODE_TYPE_USERDEF; -+ /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */ -+ if (cmd->xres == 1366 && mode->hdisplay == 1368) { -+ mode->hdisplay = 1366; -+ mode->hsync_start--; -+ mode->hsync_end--; -+ drm_mode_set_name(mode); -+ } - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - return mode; - } diff --git a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch b/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch deleted file mode 100644 index e1d1a683..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 3bfdfdcbce2796ce75bf2d85fd8471858d702e5d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= -Date: Mon, 7 Nov 2016 22:20:54 +0200 -Subject: drm/i915: Ignore bogus plane coordinates on SKL when the plane is not visible -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -From: Ville Syrjälä - -commit 3bfdfdcbce2796ce75bf2d85fd8471858d702e5d upstream. - -When the plane is invisible we may have all sorts of bogus stuff -in the coordinates, which we must ignore or else we might fail the -plane update. This started to happen on SKL when I moved the plane -offset computation to happen in the check phase. Previously we -happily ignored it all since we never called the update_plane hook -with an invisible plane. - -Cc: Sivakumar Thulasimani -Cc: drm-intel-fixes@lists.freedesktop.org -Fixes: b63a16f6cd89 ("drm/i915: Compute display surface offset in the plane check hook for SKL+") -Signed-off-by: Ville Syrjälä -Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98258 -Testcase: igt/pm_rpm/legacy-planes -Testcase: igt/pm_rpm/universal-planes -Reviewed-by: Matt Roper -Signed-off-by: Matt Roper -Link: http://patchwork.freedesktop.org/patch/msgid/1478550057-24864-3-git-send-email-ville.syrjala@linux.intel.com -(cherry picked from commit a5e4c7d0aa6784d8abe95c3ceef0da9656d17468) -Signed-off-by: Jani Nikula -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/i915/intel_display.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/gpu/drm/i915/intel_display.c -+++ b/drivers/gpu/drm/i915/intel_display.c -@@ -2975,6 +2975,9 @@ int skl_check_plane_surface(struct intel - unsigned int rotation = plane_state->base.rotation; - int ret; - -+ if (!plane_state->base.visible) -+ return 0; -+ - /* Rotate src coordinates to match rotated GTT view */ - if (intel_rotation_90_or_270(rotation)) - drm_rect_rotate(&plane_state->base.src, diff --git a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch b/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch deleted file mode 100644 index 7875c08d..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 68f458eec7069d618a6c884ca007426e0cea411b Mon Sep 17 00:00:00 2001 -From: Peter Ujfalusi -Date: Mon, 9 Jan 2017 16:31:58 +0200 -Subject: drm: Schedule the output_poll_work with 1s delay if we have delayed event - -From: Peter Ujfalusi - -commit 68f458eec7069d618a6c884ca007426e0cea411b upstream. - -Instead of scheduling the work to handle the initial delayed event, use 1s -delay. - -This delay should not be needed, but Optimus/nouveau will fail in a -mysterious way if the delayed event is handled as soon as possible like it -is done in drm_helper_probe_single_connector_modes() in case the poll -was enabled before. - -Reverting 339fd36238dd would give back the 10 sec (!) delay to handle the -delayed event. Adding 1sec delay to the poll_work is enough to work around -the issue in Optimus setups and gives shorter response on handling the -initial delayed event. - -Fixes: 339fd36238dd ("drm: drm_probe_helper: Fix output_poll_work scheduling") -Signed-off-by: Peter Ujfalusi -[danvet: Add FIXME to the comment to make it stick out more.] -Signed-off-by: Daniel Vetter -Link: http://patchwork.freedesktop.org/patch/msgid/20170109143158.21917-1-peter.ujfalusi@ti.com -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/gpu/drm/drm_probe_helper.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - ---- a/drivers/gpu/drm/drm_probe_helper.c -+++ b/drivers/gpu/drm/drm_probe_helper.c -@@ -143,8 +143,18 @@ void drm_kms_helper_poll_enable_locked(s - } - - if (dev->mode_config.delayed_event) { -+ /* -+ * FIXME: -+ * -+ * Use short (1s) delay to handle the initial delayed event. -+ * This delay should not be needed, but Optimus/nouveau will -+ * fail in a mysterious way if the delayed event is handled as -+ * soon as possible like it is done in -+ * drm_helper_probe_single_connector_modes() in case the poll -+ * was enabled before. -+ */ - poll = true; -- delay = 0; -+ delay = HZ; - } - - if (poll) diff --git a/kernel/tools/cpupowertools/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch b/kernel/tools/cpupowertools/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch deleted file mode 100644 index be9e7b23..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 2dc705a9930b4806250fbf5a76e55266e59389f2 Mon Sep 17 00:00:00 2001 -From: Kees Cook -Date: Tue, 24 Jan 2017 15:18:24 -0800 -Subject: fbdev: color map copying bounds checking - -From: Kees Cook - -commit 2dc705a9930b4806250fbf5a76e55266e59389f2 upstream. - -Copying color maps to userspace doesn't check the value of to->start, -which will cause kernel heap buffer OOB read due to signedness wraps. - -CVE-2016-8405 - -Link: http://lkml.kernel.org/r/20170105224249.GA50925@beast -Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") -Signed-off-by: Kees Cook -Reported-by: Peter Pi (@heisecode) of Trend Micro -Cc: Min Chong -Cc: Dan Carpenter -Cc: Tomi Valkeinen -Cc: Bartlomiej Zolnierkiewicz -Signed-off-by: Andrew Morton -Signed-off-by: Linus Torvalds -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/video/fbdev/core/fbcmap.c | 26 ++++++++++++++------------ - 1 file changed, 14 insertions(+), 12 deletions(-) - ---- a/drivers/video/fbdev/core/fbcmap.c -+++ b/drivers/video/fbdev/core/fbcmap.c -@@ -163,17 +163,18 @@ void fb_dealloc_cmap(struct fb_cmap *cma - - int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) - { -- int tooff = 0, fromoff = 0; -- int size; -+ unsigned int tooff = 0, fromoff = 0; -+ size_t size; - - if (to->start > from->start) - fromoff = to->start - from->start; - else - tooff = from->start - to->start; -- size = to->len - tooff; -- if (size > (int) (from->len - fromoff)) -- size = from->len - fromoff; -- if (size <= 0) -+ if (fromoff >= from->len || tooff >= to->len) -+ return -EINVAL; -+ -+ size = min_t(size_t, to->len - tooff, from->len - fromoff); -+ if (size == 0) - return -EINVAL; - size *= sizeof(u16); - -@@ -187,17 +188,18 @@ int fb_copy_cmap(const struct fb_cmap *f - - int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) - { -- int tooff = 0, fromoff = 0; -- int size; -+ unsigned int tooff = 0, fromoff = 0; -+ size_t size; - - if (to->start > from->start) - fromoff = to->start - from->start; - else - tooff = from->start - to->start; -- size = to->len - tooff; -- if (size > (int) (from->len - fromoff)) -- size = from->len - fromoff; -- if (size <= 0) -+ if (fromoff >= from->len || tooff >= to->len) -+ return -EINVAL; -+ -+ size = min_t(size_t, to->len - tooff, from->len - fromoff); -+ if (size == 0) - return -EINVAL; - size *= sizeof(u16); - diff --git a/kernel/tools/cpupowertools/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch b/kernel/tools/cpupowertools/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch deleted file mode 100644 index 454c386d..00000000 --- a/kernel/tools/cpupowertools/files/patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch +++ /dev/null @@ -1,32 +0,0 @@ -From fd7c99142d77dc4a851879a66715abf12a3193fb Mon Sep 17 00:00:00 2001 -From: Dave Martin -Date: Fri, 6 Jan 2017 17:54:51 +0000 -Subject: tile/ptrace: Preserve previous registers for short regset write - -From: Dave Martin - -commit fd7c99142d77dc4a851879a66715abf12a3193fb upstream. - -Ensure that if userspace supplies insufficient data to -PTRACE_SETREGSET to fill all the registers, the thread's old -registers are preserved. - -Signed-off-by: Dave Martin -Signed-off-by: Chris Metcalf -Signed-off-by: Greg Kroah-Hartman - ---- - arch/tile/kernel/ptrace.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/tile/kernel/ptrace.c -+++ b/arch/tile/kernel/ptrace.c -@@ -111,7 +111,7 @@ static int tile_gpr_set(struct task_stru - const void *kbuf, const void __user *ubuf) - { - int ret; -- struct pt_regs regs; -+ struct pt_regs regs = *task_pt_regs(target); - - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, - sizeof(regs)); diff --git a/kernel/tools/cpupowertools/pspec.xml b/kernel/tools/cpupowertools/pspec.xml index be4ad778..10e2decc 100644 --- a/kernel/tools/cpupowertools/pspec.xml +++ b/kernel/tools/cpupowertools/pspec.xml @@ -18,25 +18,21 @@ - patches/linux/patch-4.9.6.xz - + patches/linux/patch-4.9.18.xz + - patches/mageia/stable-fbdev-color-map-copying-bounds-checking.patch - patches/mageia/stable-tile-ptrace-preserve-previous-registers-for-short-regset-write.patch - patches/mageia/stable-drm-schedule-the-output_poll_work-with-1s-delay-if-we-have-delayed-event.patch - patches/mageia/stable-drm-fix-broken-vt-switch-with-video-1366x768-option.patch - patches/mageia/stable-drm-i915-ignore-bogus-plane-coordinates-on-skl-when-the-plane-is-not-visible.patch patches/mageia/Revert-cpufreq-pcc-Enable-autoload-of-pcc-cpufreq-fo.patch - patches/mageia/Revert-x86-mm-mtrr-Remove-kernel-internal-MTRR-inter.patch patches/mageia/base-cacheinfo-silence-DT-warnings.patch patches/mageia/pci-add-ALI-M5229-ide-compatibility-mode-quirk.patch patches/mageia/pci-quirks-drop-devinit-exit.patch + patches/mageia/pci-Blacklist-AMD-Stoney-GPU-devices-for-ATS.patch patches/mageia/acpi-CLEVO-M360S-disable_acpi_irq.patch patches/mageia/acpi-processor-M720SR-limit-to-C2.patch patches/mageia/ACPI-video-Add-a-quirk-to-force-acpi-video-backlight.patch patches/mageia/acpi-do-not-warn-if-_BQC-does-not-exist.patch + patches/mageia/acpi-ACPICA-Events-Fix-acpi_ev_initialize_region-return-v.patch + patches/mageia/block-nvme-detect-NVMe-controller-in-recent-MacBooks.patch patches/mageia/char-tpm-tpm_crb-implement-tpm-crb-idle-state.patch patches/mageia/char-tmp-tpm_crb-fix-Intel-PTT-hw-bug-during-idle-state.patch patches/mageia/char-tpm-tpm_crb-open-code-the-crb_init-into-acpi_add.patch @@ -81,10 +78,11 @@ patches/mageia/gpu-drm-mach64-linux-3.14-buildfix.patch patches/mageia/gpu-drm-mach64-3.17-buildfix.patch patches/mageia/gpu-drm-mach64-3.18-buildfix.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-A0-and-B0-revisions.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-D0-revision.patch - patches/mageia/gpu-drm-i915-skl-drop-workarounds-for-E0-revision.patch - patches/mageia/gpu-drm-i915-Remove-WaDisableLSQCROPERFforOCL-KBL-workaround.patch + patches/mageia/gpu-drm-i915-don-t-warn-about-Skylake-CPU-KabyPoint-PCH-.patch + patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-PCI-ID.patch + patches/mageia/gpu-drm-amd-amdgpu-add-Polaris12-support-v3.patch + patches/mageia/gpu-drm-amdgpu-powerplay-add-Polaris12-support.patch + patches/mageia/gpu-drm-amdgpu-pm-check-for-headless-before-calling-comp.patch patches/mageia/input-i8042-quirks-for-Fujitsu-Lifebook-A544-and-Lif.patch patches/mageia/net-sis190-fix-list-usage.patch patches/mageia/net-netfilter-IFWLOG.patch @@ -100,11 +98,14 @@ patches/mageia/net-netfilter-psd-fix-redefines.patch patches/mageia/net-wireless-rtlwifi-Use-dev_kfree_skb_irq-instead-of-kfree_skb.patch patches/mageia/net-wireless-rtlwifi-Fix-kernel-oops-introduced-with-commit-e4965.patch - patches/mageia/net-wireless-brcmfmac-fix-incorrect-event-channel-deduction.patch + patches/mageia/net-wireless-realtek-rtl8xxxu-linux-4.11-rc.patch + patches/mageia/net-wireguard.patch patches/mageia/platform-x86-add-shuttle-wmi-driver.patch patches/mageia/platform-x86-shuttle-wmi-drop-devinit-exit.patch patches/mageia/platform-x86-shuttle-wmi-4.2-buildfix.patch patches/mageia/include-kbuild-export-pci_ids.patch + patches/mageia/sound-ALSA-hda-realtek-Add-new-codec-ID-ALC299.patch + patches/mageia/sound-ALSA-hda-realtek-New-codec-support-of-ALC1220.patch patches/mageia/hid-usbhid-IBM-BladeCenterHS20-quirk.patch patches/mageia/usb-storage-unusual_devs-add-id.patch patches/mageia/usb-storage-unusual_devs-add-id-2.6.37-buildfix.patch @@ -139,7 +140,7 @@ patches/mageia/tools-build-Make-fixdep-parsing-wait-for-last-target.patch patches/mageia/tools-perf-tools-Force-fixdep-compilation-at-the-start-of-.patch patches/mageia/tools-perf-tools-Move-perf-build-related-variables-under-n.patch - + @@ -164,6 +165,13 @@ --> + + 2017-03-30 + 4.9.18 + Release bump + PisiLinux Community + admin@pisilinux.org + 2017-02-15 4.9.6