From patchwork Sat Jan 21 00:05:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Cernekee X-Patchwork-Id: 9532529 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4ECD26042D for ; Mon, 23 Jan 2017 13:29:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3A8A227D9B for ; Mon, 23 Jan 2017 13:29:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2EC762831B; Mon, 23 Jan 2017 13:29:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from emsm-gh1-uea10.nsa.gov (smtp.nsa.gov [8.44.101.8]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6431127D9B for ; Mon, 23 Jan 2017 13:29:43 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.33,274,1477958400"; d="scan'208";a="3056876" IronPort-PHdr: =?us-ascii?q?9a23=3AKWEJGBLogR+NN/Gev9mcpTZWNBhigK39O0sv0rFi?= =?us-ascii?q?tYgQKf/8rarrMEGX3/hxlliBBdydsKMYzbaH+P24EUU7or+5+EgYd5JNUxJXwe?= =?us-ascii?q?43pCcHRPC/NEvgMfTxZDY7FskRHHVs/nW8LFQHUJ2mPw6arXK99yMdFQviPgRp?= =?us-ascii?q?OOv1BpTSj8Oq3Oyu5pHfeQtFiT6ybL9oIxi7qQrdu8kKjYB/Nqs/1xzFr2dSde?= =?us-ascii?q?9L321oP1WTnxj95se04pFu9jlbtuwi+cBdT6j0Zrw0QrNEAjsoNWA1/9DrugLY?= =?us-ascii?q?TQST/HscU34ZnQRODgPY8Rz1RJbxsi/9tupgxCmXOND9QL4oVTi+6apgVRHniD?= =?us-ascii?q?0DNzUk7m/ZjMJ+h79frB64uhBz34vYbYeIP/R8Y6zdZ8sXS2pfUMhMWSJPAYSy?= =?us-ascii?q?YIkBD+oZP+tUsofwqFQSohWxGwasH/jiyiNKi3LswaE3yfgtHR/A0Qc9H9wOqn?= =?us-ascii?q?PUrNDtOakXT++10qjIzTPeZP5Ixzj98o7IfQ4iof6SQ717bM3cxlUxGAPfiFWf?= =?us-ascii?q?t4/lMC2L2ekWr2eb7/BgVeWqi24mtgFxpyKjxsA2ionGn48YzE3P+yZhwIstON?= =?us-ascii?q?G1R0F2bcSkHZdNrS2WKYR7Tt04T211oCo3yLILtYSmcCQUyJkr3R3SZvKdf4WH?= =?us-ascii?q?5h/uUvuaLy1ii3J/Yr2/gg6/8U2nyuLhSMa5yE1Kri9ZktnUsXANygDT5tCHSv?= =?us-ascii?q?Rj+keh3i6C1xzJ5eFeIEA0iLHbJ4Q9wr8wipUTsUPDEjXwmErql6+Zal8o+u2p?= =?us-ascii?q?6+Tjernmp5mcOJFoigzmL6gjlcOyDf44PwQTRWSX5+ux2KP58UHkWLlKi+c5kq?= =?us-ascii?q?jdsJDUP8Qboau5DhdO0ok97xa/DjGm0MkXnHUeN11Ffw+Hj471NF7QO/D1Fuu/?= =?us-ascii?q?glSwnzdrwPDKJLvhAo7XIXTZn7fheqh951ZGyAUv1dBf+45UCrYZLfLxXU/xss?= =?us-ascii?q?bXDgM5MwOuxebqE9d91oQYWWKKGKCZK7/SvkGS5uI0OeWMY5UVuDnlIfg/+/Hu?= =?us-ascii?q?lWM5mUMafaSx35sXamq3EehlI0WCZnrshNYBEXkRswowSOzqlVKDXiVOZ3a0Q6?= =?us-ascii?q?I8+ys3CIW8DYfMXoqtmqCO3D+nHp1KYWBLEl6NEXbsd4WBRfgMcjmfIsF/nTMZ?= =?us-ascii?q?UrihUZUu1Qm0tA/9ybpoMPbb+jECuZLkzth16PXZlQsu+jxsE8Sdz2aNQnlpkW?= =?us-ascii?q?wUQj8226Z/oVBgxlqYz6h3neZYFd1S5vNOVAc2L5jcwPJmC9rqQALOYs+JSEq6?= =?us-ascii?q?QtWhGTw+U84xzMUUY0tmB9qiiRXD0DawDL8Oi7yHHpo0/bzA33LpPcZy127G1L?= =?us-ascii?q?U9j1khWsZONWynhql59wXIAo7Jl1yVl6esdagG2i7C7n2DzWmPvEFGTgF8S6PF?= =?us-ascii?q?Um4DZkHOt9T2+lvCT6OyCbQgKgZBx9SCJbFMatL1jFVGX+zuONHGY2KwgmuwHh?= =?us-ascii?q?iJxqiWYIrtYWUd0z3XCFIYnAAL4XaGKQ8+Cz+io23EDzxuEk/vbljv8eZkq3O7?= =?us-ascii?q?SVI0wxuNb0172Lq/4gQViuCES/MPwrIEvz8spC9pE1an3tLZFcCAqhF7c6pAZN?= =?us-ascii?q?Mx+lBH1XjWtwZlJJyvM7hihkICcwRwp07u1wt4CoFEkcgtt34qyBdyKb6f0FNE?= =?us-ascii?q?bTyUx5fwOqfYKmPq5hCgd7bW2k3C0NaR4qoP8/o4q0/kvAGyCkov6G5n099S03?= =?us-ascii?q?qS45XFFgwSXYj3Ukkp6xhwv6vabTUl54PIyX1sNrG5szHY1NItGOsq1Aygf8xE?= =?us-ascii?q?PaOaCgDyCdYVB9WrKOAwnFipdB0ENvhI9KEoJ8Oma+eG2KmzMeZ8gT2pkGVH75?= =?us-ascii?q?p50k+X6yV8TevI0IofzPGDwguLTTH8g0m9ssrvg4BLeSkSHnajySjjHINRYKxy?= =?us-ascii?q?fYIPCWiwOM263c9xiID3W35f7lKjAEkG2MCxcxqIc1P9xRFQ1VgQoXG/hyu4zi?= =?us-ascii?q?B7ky0urqqFxiDB3+TidB0BOm5EX2RiiVbsIY6ugNAAW0ikdQ8plAGq5Uzi3ahU?= =?us-ascii?q?uLx/L3XPQUdPZyX2K2BiUrCstrabeM5A9pcosSRRUOShblGXUaX9owMb0yPlHm?= =?us-ascii?q?tR2Cs7eyusuprngxxwkHidI2prrHrFZcFwwg/S5MbbRf5V2joJWjN4hiXQBlmy?= =?us-ascii?q?JNSp5siUmIvYsuykUGKhTJJTezHxzYycrCu7+XFqARqnkvCrgNLnDAw63TXh2N?= =?us-ascii?q?VwTirIqxL8YpXs16S8Ku9ne1VkBFn768VmAI1+lJU/hI0I03gAmpqV5WYHkXv0?= =?us-ascii?q?MdhD2qLxcnwNRSUQzt7W/gfl3lZjLnSXyILlTHmdxdFhZ9aiaGMMxi0999xKCL?= =?us-ascii?q?uT7LFcgyt1pEe3oBnPYfh7gzgdyeEi6HgEjOEVoAAt1DmSAqgOHUlEOizhjwyI?= =?us-ascii?q?4MqjrKVTf2ugbbmw1FZ+nNy4ArGNuAdcVGz+epc4Ei969t9/P07U0H3v9oHkf8?= =?us-ascii?q?HdbcoJuR2JlxfPkfBVJ4g3lvoWmyVnI3nwvWA+y+Ellxxuxou2vJOAK2Vw5qK2?= =?us-ascii?q?HgBXNjPyZ8MJ9THik7xSnsCI0ICzBp9hACkEXIP0TfK0FzIfrfrnOByIED0grX?= =?us-ascii?q?ebHKHSHQGB50h7qHLPCYqkN2mNJHkez9VtWgWSJFBFjAATRjU6kYYzFhq2y8z5?= =?us-ascii?q?bEd5+jcR60b9qhRWzuJoMwfwUnvDpAiycDg5U56fIwRK7gFZ+0jaK9Se4fxpEy?= =?us-ascii?q?Fe4JKhsBSHKnaHaARQEWEJRkuECkj5PrW069jM6e2YCfC6L/vJYbSDsvZRWOuN?= =?us-ascii?q?xZ611Ytm5TmMPN2VPnZ+F/07xlZDXXdhFsTfgTUAUTQXlzrWYs6VpRe84DZ3rt?= =?us-ascii?q?yx8PTqXgLg/42PBKdTMdp1/xC6m6CDN/SfhCxhMzZXyosMxWPUyLgYxFMSkz9h?= =?us-ascii?q?eCKzHrQGtC7NUKXQl7RWDxEFdSx8KtFE76Um3glCIcTbkM/61qZkjv4pDFdITU?= =?us-ascii?q?Humtq3asMQLGG9LknIBFiQObSdPzLLwNz3YbmmRrFKiOVUqhuwtiyBE0P6IjSD?= =?us-ascii?q?kDrpVhCoMe1WiiGUIgBespmnchlxEWjjUM7mahqjPd9slzI236c7hnzUOm4HKj?= =?us-ascii?q?V8aFlCrqOK4iNXnPp/AHZN7nx7IumYgyyZ9fXXKo4Ksft3BSR5j/lV4HU1y7tS?= =?us-ascii?q?6iFJX+F6lzXJod5vuV6mlPODyj19UBpBsjxLnp6EvV1+OaXF8ZlNQWzL/B0X4m?= =?us-ascii?q?WOFRsHvNxlCsXxtKBWz9jAjqPzKDNZ/NLT8soQHc/UKNiIMHA5KxrmBCbUDBcZ?= =?us-ascii?q?TT6sLWzfm0tdkPSI+n2PqZg7q4bjmJwVRb9BU1w6CPAaB195E9wFJZd4Qikrka?= =?us-ascii?q?WHjMIS43qxsgXRTt1Avp/bTvKSHenvKDGBgLlHZxoIxa33IJ8WNo381UxiZEd1?= =?us-ascii?q?nJjWG0rQWtBNpzNuYhUyoEpT7Hh0Vncz1F79agOx/H8TEua5nhgohQRkZeQg7z?= =?us-ascii?q?Ts41AsJlrWviQwllIxmdbkgTyLdj7+MruwV5lMCyXor0gxLo/7QwFtYA2og0Nk?= =?us-ascii?q?LynLSKhLj7R8dWBmkxTTuZpVGfFBSq1EbgcQxeuJaPQoy1hcrDuoxVNf7+vfFZ?= =?us-ascii?q?RijBcqcYKrr39Yxg1ja9g1JarNK6VXylhQh7mDsTW22eArxw8SPUEN8HmdeCQQ?= =?us-ascii?q?okwHKqEmJza0/uxr8QGNhiFMeHYNV/U3ufJn7VkyO/6azyLn3b9DMV6+OPCCL6?= =?us-ascii?q?ODumjAic6JTkk21kwWi0lP5aJ23ts7c0qIS0Avy6OcFxoTNcXcNA5VdNBd9H7P?= =?us-ascii?q?fSaJquXA2oh6MJm4FuzySu+OrqkUiFq+HAk1B4QM8tgBHp603UHcKsfnNqAKyR?= =?us-ascii?q?Ms5QTsP1iFA/JJeA+RnDcAucG/w4d93ZNBKTEFHWV9LSK3667MpgA0hPqDXdE2?= =?us-ascii?q?YmoVX4YfKn02X8i6lDJDsHRbEDm7yOQZxxae7zXkvCTfECH8b8Z/ZPeTfR5sC8?= =?us-ascii?q?u2+DUl/KiwlV7X8o7TJ279NdR6ptDD8+UaqIibC/lMV7lyr1/cm5VER3ytS2PP?= =?us-ascii?q?Dd+1J533a4kwbdz1Cm23XUG+izM1Vcj+J8yhLq6WjgH0XYxUqpWU3Cg/Nc+hET?= =?us-ascii?q?ETAw1/p+UC5K1gewIMe587YB7utwQ5MaywOhyV3c6vQ2m3LztaVvdfzfiga7xR?= =?us-ascii?q?0SUscvewyGE8QZEi0+m37UkNSYkRgR7Aw/aufJNRXjXtGnNDYQXPvjA2l3JhN+?= =?us-ascii?q?ooxec/2hzIu0EGMz+XbOxpdHBEv9YkCFOdPHV2C244R1uCgorG+QOjwq4d8DBc?= =?us-ascii?q?n9lO1+1Jqn/+voXQYDi0QqyktY3VszY8bdghu6BxK4rjIsqau5PemTzfSILQvB?= =?us-ascii?q?WcXiCnDfRXht9eLTlET/lPnGEqJdYJuZFd6UYrUMcxOaBPArE2pr+2cTpkETIS?= =?us-ascii?q?zSgBWoOawTMNn/yx27TflhafapgiNgILsIlaiNsHTyF2ej8epLOkV4jOjW+LUH?= =?us-ascii?q?ILIAAI4glX+AIAjJV/fv7774rMTZ9MzTFWo/Z1UivEFplo61X7RXuMgVj9Uvmh?= =?us-ascii?q?lfKm3R5KxvL2ztYbQAJ/CVRax+tOmEokMq14K6kRvo7Psz+Hb0D6sXnsyOS4Ol?= =?us-ascii?q?Ze19fYd1riDIrKrWD8SDET+WUIRY9Tz3HSDY4dkxBkaKYtvllMI5urekf/5zwl?= =?us-ascii?q?24RmBKO0Vca1yFY5tXwGXTulE8JdC+F6t1LaQDxlY5a3qJr7P5VdXGpQ94OBq1?= =?us-ascii?q?dDkERgKCm5yYJCJMFL5z4DRjlPoTGGs9u1R8xPw8h2D4UDIt1noXfyBLtEOISN?= =?us-ascii?q?o30xorHvxWXZ9Co6sFem3zizGqi4Tuxf/20CGgUmOWWeqk8zD+Qy6Gfe6FbNvU?= =?us-ascii?q?5o/+1DHLiAkV1xoCphHpBJHjtJyXelL1FoQXlar+laLb/af9ZaQ/YseR+lIwY+?= =?us-ascii?q?GuI+30yV4UF0mm/0YyxouQtA4S/dWxQ7WDIIjbjzgT0est+oOTsERJJSdzkhaD?= =?us-ascii?q?3FKw2DkyBNoBlfc11qW4weAttd+bEb2pVb89HfRkmyMiEKQgZiNh4m3vVCj0JD?= =?us-ascii?q?tluXeTzFBwqyafnPqgF3fduWrMOxN/v58htIhp/lvewl+agOXGGpmQqoQd/CtY?= =?us-ascii?q?D8rcGKulGIdKjmL+22eWXBQyTUjRCsmbckCIHH/zLNPwVGK5l102YkbIPlCW7M?= =?us-ascii?q?IxRJObwXKFZcVa9nd9pKuOZaaNF4eKwR469iGgqHRg/zGIyotPRGNk3TRSjEIC?= =?us-ascii?q?qc7uyyupnT7bvASej6esOD2XDHQ75tPphg7Tn3AbDq0ZVR+kDuwPdi6lt6SUTa?= =?us-ascii?q?MyCGtNnhOhkL69e8eUT/pZApADfWAItqkHX32EFAds0XQym0/5QE0p9Z72zwSe?= =?us-ascii?q?1g2EjprOJS76Vk6ZUw471x1Mi0I73dJO9Hvk9hGBeYHAJq9o8iAGJnXWBefvcR?= =?us-ascii?q?KOvNfaQelc3uqfr4F7YQ6B2O/+xWc8XHKlrEmsmiDjGcVR1EkxsAqTEAKAuczO?= =?us-ascii?q?SJm6huScaqveL5wF4i40CiLh4ay7Bg/YWE9bCOpO/ZdRvRyqULVbbxS8PvtLss?= =?us-ascii?q?vViS5fo+mL4IZGN1fxWtEPIBWc4F2mfg0acqwDoqE8PHBL/g+fhDV3cjkjLhnZ?= =?us-ascii?q?B9EU8WFekPHbqX54Reg3s3m/DENt0MbK9OgGGPFQSrErUa036k9zOXIHV5ghHJ?= =?us-ascii?q?yxzwR2Kz40PxrS98WyTM1M3vkktSVrmwHkdSRDGkOUp3vTKAJgbos8D3uast5k?= =?us-ascii?q?EsLmPkrM6NlHemOL5PA8LwPticLjcvpFILjJwxQcei2ZsHFtq8PtgR9m1+bvrE?= =?us-ascii?q?5G+xlS9OvbtHjZLE4s6J4vXXAWWgj6qCprWJ3zBYz3g1sEox6t++K/7O4MeKTO?= =?us-ascii?q?6w12YLSCd/uRXOUAKpqrDBqFAUI0OL2l/RmIMWJtFZwWU41kb+6eghQdIz8R5T?= =?us-ascii?q?FoPeaPICuz/zIjr0wVCQY94tUCmRzSdXFErvEVZkAKg8xH7wvMXRmHfR+lwnXJ?= =?us-ascii?q?N/eFD8iBxsEYo4NVwi50QNzioECwgNZgiRDKu0CkT9MYsESU8DZAyc07i7Yac2?= =?us-ascii?q?01d8wrGu5O/PdexzHbcNNvJGgwGSm1hUB4wZvrcDQLJmfF9d7rTYqhLlC4j9UP?= =?us-ascii?q?jsjWAwOuGtQsBG7cAZsGMv4h6lSBq89ZhD77gaiJeSdq5HeJTMp95z70Nm5T4J?= =?us-ascii?q?ayxMjwNyjwujXuAAuO/j4tbasJ2y6uatTqotRPsY9wIyB2tgi5v8mlcjocvY1+?= =?us-ascii?q?1EUI3alZz/8BxRI36NoIvazwN8JvQKK42xerZv6W4KKDUfJ3IBPNqWd+Mz4zR3?= =?us-ascii?q?PzXJ+lxOGMUMas0EPMDVgwBbllXpWK1P9srcAlKYBJ18d9o24GrryDA46p88Uu?= =?us-ascii?q?f86DCoJZDQ9UxNP+hZgCVqit3CuPAfweDOBygP/XmZdx91zzuNy5aTDfbw4eKM?= =?us-ascii?q?yNbTW1MdACE2V4ZdJDyf+Q2oXee1kIvmUhmU68Dpmp4+clyfRmCplqQfrqlMCf?= =?us-ascii?q?JAijn83jVGCo/1heiavMa35WRLsV1HFIJz7RzbF6VFIpV0Jwj3lsmxSkh7HCv/?= =?us-ascii?q?d9nedgAyt+qO2ucM/+J+OlP7ZY8cJBIE17365mROQwtrSb75pFCZUvwNZNpoT/?= =?us-ascii?q?PEtHNV6Zl6J68JIleduITgri1Up1AuHA8pdLgwoyRVdkbShw1VQL/4tqMPhAUa?= =?us-ascii?q?UN55v1JMGG2rNWIx4jrIT6JVg7eLBPwS6DWTQbQEU190PSNmXxO1xJJudqOrnf?= =?us-ascii?q?BAsmNGmDlxr+Qq0zxiWRuzpCztp6ML2TI7+7G4tS4MuWJETuWAiSjIDUhMzPUQ?= =?us-ascii?q?gacaFXni9US2YGMfY4vq/LlnOcPg+JEg43QhexojeTYLXeC9Cy7tjqOIBZePvM?= =?us-ascii?q?hbhB6Xt8XEdaWzIjQKNrQh1RLjQGBw0grAkxZm/msLRi6t7dE+K4W7J8kl2jCk?= =?us-ascii?q?GW7Fe1YQ+qlJqtf+tUYXTOsqblNs2Gpj0syARiwDWsPPH2I1gxM/aWVDdpJD6A?= =?us-ascii?q?MVG7MugjmWoqlM5hsUbyvMEoS55onQmt/F2Xs9TdZq3mLWoamFhpI20HJ7gN50?= =?us-ascii?q?6y+OuGgId+PGScNsBWLz1ohHw+zke/qtqvwHSJdhyLm5TP8CM8yj9HCq2JVrRk?= =?us-ascii?q?ClxaoRH16jPO8F2LjbTz+vSXeEVuSTb2iMgzE5P1b35RmpLV03a8BKolQ/MuTY?= =?us-ascii?q?hZ5ckAvhXq1yRimKo1/U0nAjO/sAdw0qoIenZxAKTOkJaueHO+cuxuE+BUAXb3?= =?us-ascii?q?/NGit2F/O2sUCzk4dmIXlg5l/6Yev1+AD8LNSSAgUEEZLdrpNp4fy6QWaBNmV6?= =?us-ascii?q?zBx8O0l08+nfGk80tu9bdJaRhsbfiMhh0e4CbPdtKiw9utgcmo557omUysiKew?= =?us-ascii?q?nLzpnuPdHVvuSYA/rHwkQkZG5aVrsZYRvr6IghP985WrjTHb5HshQGAag1XoYt?= =?us-ascii?q?N2Dr9KF7NAlzaBLeZKyogsn2oeKGfpVVp2fM7lIxMCjTpQYOyvm1TQxndZClmW?= =?us-ascii?q?/+IJcqRjJOt9dtEAdpHJNTG8McqAqqG5mUmKWlhNKq40N6v/UFsbHsCvDLyNu5?= =?us-ascii?q?w59xUIZE6kCROjbeGrVriFx/juuumvfAzoXxCcT6dNMAVeh7RHPFa7DfEoW7Kz?= =?us-ascii?q?KOId78e1Vd/r6dyr15VBKRaDr+X6qcuy2uLO9k7lkjyoxkYOrTyyQg76rF19v2?= =?us-ascii?q?ZmFboDqjrHGOOJVQ8FzKBfLRXwhKRvqd6mloBq4XYpXu9OcIL9MixMOT4xR87D?= =?us-ascii?q?hY18uFOaehpFfW2k1nbZLbMFfp2yEhVIkPOhuwLUssgW7fqnTaGnlcMMmkKc9z?= =?us-ascii?q?j9aRDxzt4VRxmG43am5GAGroSs+bOXIH1MKmeA2K6AVLAs4Bn+Gtek44sba9RP?= =?us-ascii?q?J1OpVDheWqtLIHkctmKyHPWMhWJSfQI6FqPjBJFOXAuEAoYgIYs7gyQoo6foOB?= =?us-ascii?q?LEQDMEeB0iPy0RDC3Vfvd9OyyKmFOj0W/WtDz7LE1zhMuga4tO2FjczjSrDZcY?= =?us-ascii?q?r2UOTcMSU/SjGaXjMyEUCz9VejofoEs+KSIX0DrVAMfiKSFAkTq7hgrdfKFWDT?= =?us-ascii?q?g+xjc4MOhP2BRSDwTDd3lLEzBiZWr0yMReQMFRXOZX/7nGVcoBCiJuNL/X/9bb?= =?us-ascii?q?2Yw61VW/YMAotNaf2UWN3YdupbJzg2lzUVIuG8f8fTr7whyFLHUXMZE7XU9F2Z?= =?us-ascii?q?VEOWWfKcxzf3UogUvIU5oTQo9czKni92EqXIOLCfqySo8oGmkCaSoffeWXU1Y0?= =?us-ascii?q?wpnOICB3GMwBtHKGECD9EYo0TtTbCdaEZC03Ipk/5h1AEWdAR1THJuzi4eoPHo?= =?us-ascii?q?AdFUR1AZiiWtRPQdd11tEBsr8ESX5ADuJ9cHvISbR2JE/LYWVaISK/8k75ORMb?= =?us-ascii?q?MZxv9v2yhp5iUn922RBk1QiyqJ+rTdGaZ7yKEE42Qku7luV1yLayvWb2yCz42h?= =?us-ascii?q?Ec8JziBr5Tj/29H8ovFmNLwcoZpwRlgNH2Y+K8jU5zFaeXn9wgqppxKyFznYJy?= =?us-ascii?q?gWsxgRIilQVetrzukzmxvScNvC5E7Y46kssk2mCguGIrG0wptOC9zskwKiZn8Y?= =?us-ascii?q?In2QC5lqp6MVx54paqQ9aN37WgjM?= X-IPAS-Result: =?us-ascii?q?A2GrAwBABIZY/wHyM5BdGgEBAQECAQEBAQgBAQEBFQEBAQE?= =?us-ascii?q?CAQEBAQgBAQEBgxIBAQEBAR+BaY5NoW6GXSKHdFcBAQEBAQEBAQIBAmAogjMbg?= =?us-ascii?q?hwGAQIXDRMUIAsDAwkBARcpCAgDAS0DAQUBCxEHBwsFGASIa59iP41tOiYCiiI?= =?us-ascii?q?mEo9CAhEBhgABBJAqiyGRXYouJoYnSJBoMoEUWHM3Kgg6hDYDHIICUoVGDxeCF?= =?us-ascii?q?wEBAQ?= Received: from unknown (HELO tarius.tycho.ncsc.mil) ([144.51.242.1]) by emsm-gh1-uea10.nsa.gov with ESMTP; 23 Jan 2017 13:29:42 +0000 Received: from prometheus.infosec.tycho.ncsc.mil (prometheus [192.168.25.40]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id v0NDTfav009594; Mon, 23 Jan 2017 08:29:41 -0500 Received: from tarius.tycho.ncsc.mil (tarius.infosec.tycho.ncsc.mil [144.51.242.1]) by prometheus.infosec.tycho.ncsc.mil (8.15.2/8.15.2) with ESMTP id v0L06XFU040443 for ; Fri, 20 Jan 2017 19:06:33 -0500 Received: from goalie.tycho.ncsc.mil (goalie [144.51.242.250]) by tarius.tycho.ncsc.mil (8.14.4/8.14.4) with ESMTP id v0L06RNh009764 for ; Fri, 20 Jan 2017 19:06:33 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A1CJAQBMpYJYhjFTfUpeHAEBBAEBCgEBgz0BAQEBAYIIsDuCRIQ2iB9XAQIBAQEBAQITAQEBCAsLCh2FGgYaDVIQUTQBBQEcBxKJBqJmP41tOop6CQEIj0KGFAWQKYsfkVqKLoZNSJBmMoEUgX8qCIQkAUsDHIIBHTWGbII9AQEB X-IPAS-Result: A1CJAQBMpYJYhjFTfUpeHAEBBAEBCgEBgz0BAQEBAYIIsDuCRIQ2iB9XAQIBAQEBAQITAQEBCAsLCh2FGgYaDVIQUTQBBQEcBxKJBqJmP41tOop6CQEIj0KGFAWQKYsfkVqKLoZNSJBmMoEUgX8qCIQkAUsDHIIBHTWGbII9AQEB X-IronPort-AV: E=Sophos;i="5.33,260,1477972800"; d="scan'208";a="5915767" Received: from emsm-gh1-uea10.corp.nsa.gov (HELO emsm-gh1-uea10.nsa.gov) ([10.208.41.36]) by goalie.tycho.ncsc.mil with ESMTP; 20 Jan 2017 19:06:29 -0500 IronPort-PHdr: =?us-ascii?q?9a23=3AdVjF2xDv3SRZqFA/EFe5UyQJP3N1i/DPJgcQr6Af?= =?us-ascii?q?oPdwSPT5pMbcNUDSrc9gkEXOFd2CrakV16yK7+u6BSQp2tWoiDg6aptCVhsI24?= =?us-ascii?q?09vjcLJ4q7M3D9N+PgdCcgHc5PBxdP9nC/NlVJSo6lPwWB6nK94iQPFRrhKAF7?= =?us-ascii?q?Ovr6GpLIj8Swyuu+54Dfbx9GiTe5br5+Nhq7oAreusUIjoZpN7o8xAbOrnZUYe?= =?us-ascii?q?pd2HlmJUiUnxby58ew+IBs/iFNsP8/9MBOTLv3cb0gQbNXEDopPWY15Nb2tRbY?= =?us-ascii?q?VguA+mEcUmQNnRVWBQXO8Qz3UY3wsiv+sep9xTWaMMjrRr06RTiu86FmQwLuhS?= =?us-ascii?q?waNTA27XvXh9RwgqxFvRyvqR9xzYnWb4GbL/dyYr/RcMkGSWdbQspdSypMCZ68?= =?us-ascii?q?YYsVCOoBOP5VoYzjqFsQrBu+AxSnCf3xxT9SgH/5w6463Po/Hgrb2wEvA8wBsG?= =?us-ascii?q?7SrNrrN6cdT/66wbLUwjXDdfNW3jL96InVchAku/2MWqhwccXIxEQpCgjLjU2Q?= =?us-ascii?q?pJTnMj6azOgBrnaX4up6We+shWMrsQ58rzypy8wxkIfGnJgVxUrB9ShhwIY6O9?= =?us-ascii?q?m4SEljbN6hCpRQtiWaO5JuQsMtX21koSg6x7ICtJKhcygKz5MnxxHba/OZaYSH?= =?us-ascii?q?/hXjVOOJLTd5gnJqZq6/ig6w/EWv0OHwS9e43VZQoidGnNTArH8A2hjL5siCUP?= =?us-ascii?q?R9/0Oh2TiV1wDU7+FJOVw7mrTBK54n3LEwlYQcvlrYEy/5n0X2i6CWdkE69eSy?= =?us-ascii?q?9+vnZbDmqoeGN4BokgH+LrgumsunDOQjLAcOW2mb+eKh1Lzs5kD5XLVLgeE2kq?= =?us-ascii?q?neqpzaI98bqbSjDw9a1YYj9UX3MzDzy8gVk3cKKhRGfBuclIXzJ3nVLfvlC/qj?= =?us-ascii?q?xV+rlXMjx/3cNLD7Hr3CKX7Pl62ndK507UcazxA8i9lCo9pYA68MJdr/U1H8sd?= =?us-ascii?q?jfAAN/NQGoh67/Ach5/psXRGbKB6ieKq6UuliNoqo0L/KkeJ4euDG7LeMsofHp?= =?us-ascii?q?kztxlEcUZ6iy9YMecnGjBvBvKEjfZmDj0fkbFmJfnQcgTeqio1CYVzNQanv6C6?= =?us-ascii?q?kx/Dc2C4+rJYzDXIeogaGEmiChEcsFNSh9FlmQHCKwJM2/UPAWZXfKLw=3D=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0EeAgBMpYJYhjFTfUpeHAEBBAEBCgEBF?= =?us-ascii?q?wEBBAEBCgEBgxIBAQEBAYIIsDuCRIQ2iB9XAQEBAQEBAQECAQIQAQEBCAsLCh0?= =?us-ascii?q?wgjMZgh4GGg1SEFE0AQUBHAcSiQaiZj+NbTqKegkBCI9ChhQFkCmLH5Faii6GT?= =?us-ascii?q?UiQZjKBFIIAKgiEJAFLAxyCAR01hmyCPQEBAQ?= X-IPAS-Result: =?us-ascii?q?A0EeAgBMpYJYhjFTfUpeHAEBBAEBCgEBFwEBBAEBCgEBgxI?= =?us-ascii?q?BAQEBAYIIsDuCRIQ2iB9XAQEBAQEBAQECAQIQAQEBCAsLCh0wgjMZgh4GGg1SE?= =?us-ascii?q?FE0AQUBHAcSiQaiZj+NbTqKegkBCI9ChhQFkCmLH5Faii6GTUiQZjKBFIIAKgi?= =?us-ascii?q?EJAFLAxyCAR01hmyCPQEBAQ?= X-IronPort-AV: E=Sophos;i="5.33,260,1477958400"; d="scan'208";a="3033694" X-IronPort-Outbreak-Status: No, level 0, Unknown - Unknown Received: from mail-pg0-f49.google.com ([74.125.83.49]) by emsm-gh1-uea10.nsa.gov with ESMTP/TLS/AES128-GCM-SHA256; 21 Jan 2017 00:06:28 +0000 Received: by mail-pg0-f49.google.com with SMTP id 194so27300804pgd.2 for ; Fri, 20 Jan 2017 16:06:28 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=a83Ws47cQ4580jUe5tW3H2sd6ii8yg9FmU2iGJQ+Dfw=; b=P96Wz6/fFrArTEPiNe1ntFGvmYW34wX/batTE6ED/J7XKAzLPufq0HmF0lqdNksgv4 OsPI5X35hMqgEgaQ8AQqZykg6SyzbLL7DNZOTyTHVZLyOKB5wAmPpqMuvQOmwWb8f9eR XgknOFFg21a2sDgXSucqXFSrHp2DDLgTrsN/PxLfhzytXP2i1GvbwQSwBFalKGrXiwSa MHfnQzl7gpDauBkIzKB0VqyVuLzQ2yfw3teQcmrqEHzynnADxoAFyRrVRaz4J/Ex40wy dDK1H5SNJcOxWMQWKIY/cpM+cmBo/KiUmJSiHEiSdjg9g07yB+GkKskhqi26o2pLGdsv ONfQ== X-Gm-Message-State: AIkVDXID6PeN4FURI8YNvzhCpvyy618bEgTZjTU3bZaHLO+MiKC/nPmE5P2nooqVoGURrE83 X-Received: by 10.99.147.81 with SMTP id w17mr19954313pgm.111.1484957187243; Fri, 20 Jan 2017 16:06:27 -0800 (PST) Received: from kcl.mtv.corp.google.com ([172.22.66.15]) by smtp.gmail.com with ESMTPSA id 66sm19375359pfx.29.2017.01.20.16.06.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 20 Jan 2017 16:06:26 -0800 (PST) From: Kevin Cernekee To: steffen.klassert@secunet.com, herbert@gondor.apana.org.au, davem@davemloft.net, paul@paul-moore.com, sds@tycho.nsa.gov, eparis@parisplace.org Subject: [PATCH 3/4] xfrm_user: Initial commit of xfrm_user_legacy.c Date: Fri, 20 Jan 2017 16:05:06 -0800 Message-Id: <20170121000507.34381-4-cernekee@chromium.org> X-Mailer: git-send-email 2.11.0.483.g087da7b7c-goog In-Reply-To: <20170121000507.34381-1-cernekee@chromium.org> References: <20170121000507.34381-1-cernekee@chromium.org> X-Mailman-Approved-At: Mon, 23 Jan 2017 08:28:53 -0500 X-BeenThere: selinux@tycho.nsa.gov X-Mailman-Version: 2.1.20 Precedence: list List-Id: "Security-Enhanced Linux \(SELinux\) mailing list" List-Post: List-Help: Cc: netdev@vger.kernel.org, fw@strlen.de, dianders@chromium.org, linux-kernel@vger.kernel.org, selinux@tycho.nsa.gov, fan.du@windriver.com, dtor@chromium.org MIME-Version: 1.0 Errors-To: selinux-bounces@tycho.nsa.gov Sender: "Selinux" X-Virus-Scanned: ClamAV using ClamSMTP Several xfrm_* structs are incompatible between 32bit and 64bit builds: xfrm_usersa_info 220 bytes on i386 -> 224 bytes on amd64 xfrm_userpolicy_info 164 -> 168 xfrm_userspi_info 228 -> 232, offset mismatch on min xfrm_user_acquire 276 -> 280, offset mismatch on aalgos xfrm_user_expire 224 -> 232, offset mismatch on hard xfrm_user_polexpire 168 -> 176, offset mismatch on hard Fork all of the functions that handle these structs into a new file so that it is possible to support both legacy + new layouts. This commit contains an exact copy of the necessary functions from xfrm_user.c, for ease of reviewing. The next commit will contain all of the changes needed to make these functions handle legacy messages correctly. Signed-off-by: Kevin Cernekee --- net/xfrm/Kconfig | 14 + net/xfrm/Makefile | 8 +- net/xfrm/xfrm_user_legacy.c | 1091 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1112 insertions(+), 1 deletion(-) create mode 100644 net/xfrm/xfrm_user_legacy.c diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index bda1a13628a8..317dcc411345 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -20,6 +20,20 @@ config XFRM_USER If unsure, say Y. +config XFRM_USER_LEGACY + tristate "Legacy transformation user configuration interface" + depends on XFRM_USER + default y + ---help--- + The original Transformation(XFRM) netlink messages were not + compatible between 32-bit programs and 64-bit kernels, so they + have been deprecated. Enable this option if you have existing + binaries that rely on the old format messages. Disable this + option if you know that all users of the interface have been + built against recent kernel headers. + + If unsure, say Y. + config XFRM_SUB_POLICY bool "Transformation sub policy support" depends on XFRM diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index c0e961983f17..6cf6f8da3dc8 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -7,5 +7,11 @@ obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ xfrm_sysctl.o xfrm_replay.o obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o -obj-$(CONFIG_XFRM_USER) += xfrm_user.o + +xfrm-user-objs := xfrm_user.o +ifneq ($(CONFIG_XFRM_USER_LEGACY),) +xfrm-user-objs += xfrm_user_legacy.o +endif +obj-$(CONFIG_XFRM_USER) += xfrm-user.o + obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o diff --git a/net/xfrm/xfrm_user_legacy.c b/net/xfrm/xfrm_user_legacy.c new file mode 100644 index 000000000000..058accfefc83 --- /dev/null +++ b/net/xfrm/xfrm_user_legacy.c @@ -0,0 +1,1091 @@ +/* xfrm_user.c: User interface to configure xfrm engine. + * + * Copyright (C) 2002 David S. Miller (davem@redhat.com) + * + * Changes: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xfrm_user.h" + +static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + const struct xfrm_usersa_info *p = nlmsg_data(nlh); + struct xfrm_state *x; + int err; + struct km_event c; + + err = xfrm_verify_newsa_info(p, attrs); + if (err) + return err; + + x = xfrm_state_construct(net, p, attrs, &err); + if (!x) + return err; + + xfrm_state_hold(x); + if (nlh->nlmsg_type == XFRM_MSG_NEWSA) + err = xfrm_state_add(x); + else + err = xfrm_state_update(x); + + xfrm_audit_state_add(x, err ? 0 : 1, true); + + if (err < 0) { + x->km.state = XFRM_STATE_DEAD; + __xfrm_state_put(x); + goto out; + } + + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + c.event = nlh->nlmsg_type; + + km_state_notify(x, &c); +out: + xfrm_state_put(x); + return err; +} + +static int xfrm_del_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state *x; + int err = -ESRCH; + struct km_event c; + const struct xfrm_usersa_id *p = nlmsg_data(nlh); + + x = xfrm_user_state_lookup(net, p, attrs, &err); + if (x == NULL) + return err; + + if ((err = security_xfrm_state_delete(x)) != 0) + goto out; + + if (xfrm_state_kern(x)) { + err = -EPERM; + goto out; + } + + err = xfrm_state_delete(x); + + if (err < 0) + goto out; + + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + c.event = nlh->nlmsg_type; + km_state_notify(x, &c); + +out: + xfrm_audit_state_delete(x, err ? 0 : 1, true); + xfrm_state_put(x); + return err; +} + +static void copy_to_user_state(const struct xfrm_state *x, + struct xfrm_usersa_info *p) +{ + memset(p, 0, sizeof(*p)); + memcpy(&p->id, &x->id, sizeof(p->id)); + memcpy(&p->sel, &x->sel, sizeof(p->sel)); + memcpy(&p->lft, &x->lft, sizeof(p->lft)); + memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); + put_unaligned(x->stats.replay_window, &p->stats.replay_window); + put_unaligned(x->stats.replay, &p->stats.replay); + put_unaligned(x->stats.integrity_failed, &p->stats.integrity_failed); + memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); + p->mode = x->props.mode; + p->replay_window = x->props.replay_window; + p->reqid = x->props.reqid; + p->family = x->props.family; + p->flags = x->props.flags; + p->seq = x->km.seq; +} + +static int copy_to_user_state_extra(const struct xfrm_state *x, + struct xfrm_usersa_info *p, + struct sk_buff *skb) +{ + int ret = 0; + + copy_to_user_state(x, p); + + if (x->props.extra_flags) { + ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS, + x->props.extra_flags); + if (ret) + goto out; + } + + if (x->coaddr) { + ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); + if (ret) + goto out; + } + if (x->lastused) { + ret = nla_put_u64_64bit(skb, XFRMA_LASTUSED, x->lastused, + XFRMA_PAD); + if (ret) + goto out; + } + if (x->aead) { + ret = nla_put(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); + if (ret) + goto out; + } + if (x->aalg) { + ret = xfrm_copy_to_user_auth(x->aalg, skb); + if (!ret) + ret = nla_put(skb, XFRMA_ALG_AUTH_TRUNC, + xfrm_alg_auth_len(x->aalg), x->aalg); + if (ret) + goto out; + } + if (x->ealg) { + ret = nla_put(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); + if (ret) + goto out; + } + if (x->calg) { + ret = nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); + if (ret) + goto out; + } + if (x->encap) { + ret = nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); + if (ret) + goto out; + } + if (x->tfcpad) { + ret = nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad); + if (ret) + goto out; + } + ret = xfrm_mark_put(skb, &x->mark); + if (ret) + goto out; + if (x->replay_esn) + ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL, + xfrm_replay_state_esn_len(x->replay_esn), + x->replay_esn); + else + ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), + &x->replay); + if (ret) + goto out; + if (x->security) + ret = xfrm_copy_sec_ctx(x->security, skb); +out: + return ret; +} + +static int dump_one_state(const struct xfrm_state *x, int count, void *ptr) +{ + struct xfrm_dump_info *sp = ptr; + struct sk_buff *in_skb = sp->in_skb; + struct sk_buff *skb = sp->out_skb; + struct xfrm_usersa_info *p; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq, + XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); + if (nlh == NULL) + return -EMSGSIZE; + + p = nlmsg_data(nlh); + + err = copy_to_user_state_extra(x, p, skb); + if (err) { + nlmsg_cancel(skb, nlh); + return err; + } + nlmsg_end(skb, nlh); + return 0; +} + +static int xfrm_dump_sa_done(struct netlink_callback *cb) +{ + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; + struct sock *sk = cb->skb->sk; + struct net *net = sock_net(sk); + + if (cb->args[0]) + xfrm_state_walk_done(walk, net); + return 0; +} + +static const struct nla_policy xfrma_policy[XFRMA_MAX+1]; +static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; + struct xfrm_dump_info info; + + BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + + info.in_skb = cb->skb; + info.out_skb = skb; + info.nlmsg_seq = cb->nlh->nlmsg_seq; + info.nlmsg_flags = NLM_F_MULTI; + + if (!cb->args[0]) { + struct nlattr *attrs[XFRMA_MAX+1]; + struct xfrm_address_filter *filter = NULL; + u8 proto = 0; + int err; + + err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX, + xfrma_policy); + if (err < 0) + return err; + + if (attrs[XFRMA_ADDRESS_FILTER]) { + filter = kmemdup(nla_data(attrs[XFRMA_ADDRESS_FILTER]), + sizeof(*filter), GFP_KERNEL); + if (filter == NULL) + return -ENOMEM; + } + + if (attrs[XFRMA_PROTO]) + proto = nla_get_u8(attrs[XFRMA_PROTO]); + + xfrm_state_walk_init(walk, proto, filter); + cb->args[0] = 1; + } + + (void) xfrm_state_walk(net, walk, dump_one_state, &info); + + return skb->len; +} + +static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, + const struct xfrm_state *x, + u32 seq) +{ + struct xfrm_dump_info info; + struct sk_buff *skb; + int err; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + info.in_skb = in_skb; + info.out_skb = skb; + info.nlmsg_seq = seq; + info.nlmsg_flags = 0; + + err = dump_one_state(x, 0, &info); + if (err) { + kfree_skb(skb); + return ERR_PTR(err); + } + + return skb; +} + +static int xfrm_get_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + const struct xfrm_usersa_id *p = nlmsg_data(nlh); + struct xfrm_state *x; + struct sk_buff *resp_skb; + int err = -ESRCH; + + x = xfrm_user_state_lookup(net, p, attrs, &err); + if (x == NULL) + goto out_noput; + + resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err = PTR_ERR(resp_skb); + } else { + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); + } + xfrm_state_put(x); +out_noput: + return err; +} + +static int xfrm_alloc_userspi(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state *x; + const struct xfrm_userspi_info *p; + struct sk_buff *resp_skb; + const xfrm_address_t *daddr; + int family; + int err; + u32 mark; + struct xfrm_mark m; + + p = nlmsg_data(nlh); + err = verify_spi_info(p->info.id.proto, p->min, p->max); + if (err) + goto out_noput; + + family = p->info.family; + daddr = &p->info.id.daddr; + + x = NULL; + + mark = xfrm_mark_get(attrs, &m); + if (p->info.seq) { + x = xfrm_find_acq_byseq(net, mark, p->info.seq); + if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) { + xfrm_state_put(x); + x = NULL; + } + } + + if (!x) + x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, + p->info.id.proto, daddr, + &p->info.saddr, 1, + family); + err = -ENOENT; + if (x == NULL) + goto out_noput; + + err = xfrm_alloc_spi(x, p->min, p->max); + if (err) + goto out; + + resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err = PTR_ERR(resp_skb); + goto out; + } + + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); + +out: + xfrm_state_put(x); +out_noput: + return err; +} + +static void copy_to_user_policy(const struct xfrm_policy *xp, + struct xfrm_userpolicy_info *p, + int dir) +{ + memset(p, 0, sizeof(*p)); + memcpy(&p->sel, &xp->selector, sizeof(p->sel)); + memcpy(&p->lft, &xp->lft, sizeof(p->lft)); + memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); + p->priority = xp->priority; + p->index = xp->index; + p->sel.family = xp->family; + p->dir = dir; + p->action = xp->action; + p->flags = xp->flags; + p->share = XFRM_SHARE_ANY; /* XXX xp->share */ +} + +static int xfrm_add_policy(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + const struct xfrm_userpolicy_info *p = nlmsg_data(nlh); + struct xfrm_policy *xp; + struct km_event c; + int err; + int excl; + + err = xfrm_verify_newpolicy_info(p); + if (err) + return err; + err = xfrm_verify_sec_ctx_len(attrs); + if (err) + return err; + + xp = xfrm_policy_construct(net, p, attrs, &err); + if (!xp) + return err; + + /* shouldn't excl be based on nlh flags?? + * Aha! this is anti-netlink really i.e more pfkey derived + * in netlink excl is a flag and you wouldnt need + * a type XFRM_MSG_UPDPOLICY - JHS */ + excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; + err = xfrm_policy_insert(p->dir, xp, excl); + xfrm_audit_policy_add(xp, err ? 0 : 1, true); + + if (err) { + security_xfrm_policy_free(xp->security); + kfree(xp); + return err; + } + + c.event = nlh->nlmsg_type; + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + km_policy_notify(xp, p->dir, &c); + + xfrm_pol_put(xp); + + return 0; +} + +static inline size_t userpolicy_type_attrsize(void) +{ +#ifdef CONFIG_XFRM_SUB_POLICY + return nla_total_size(sizeof(struct xfrm_userpolicy_type)); +#else + return 0; +#endif +} + +static int dump_one_policy(const struct xfrm_policy *xp, + int dir, + int count, + void *ptr) +{ + struct xfrm_dump_info *sp = ptr; + struct xfrm_userpolicy_info *p; + struct sk_buff *in_skb = sp->in_skb; + struct sk_buff *skb = sp->out_skb; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq, + XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); + if (nlh == NULL) + return -EMSGSIZE; + + p = nlmsg_data(nlh); + copy_to_user_policy(xp, p, dir); + err = xfrm_copy_to_user_tmpl(xp, skb); + if (!err) + err = copy_to_user_sec_ctx(xp, skb); + if (!err) + err = copy_to_user_policy_type(xp->type, skb); + if (!err) + err = xfrm_mark_put(skb, &xp->mark); + if (err) { + nlmsg_cancel(skb, nlh); + return err; + } + nlmsg_end(skb, nlh); + return 0; +} + +static int xfrm_dump_policy_done(struct netlink_callback *cb) +{ + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + struct net *net = sock_net(cb->skb->sk); + + xfrm_policy_walk_done(walk, net); + return 0; +} + +static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + struct xfrm_dump_info info; + + BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + + info.in_skb = cb->skb; + info.out_skb = skb; + info.nlmsg_seq = cb->nlh->nlmsg_seq; + info.nlmsg_flags = NLM_F_MULTI; + + if (!cb->args[0]) { + cb->args[0] = 1; + xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); + } + + (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); + + return skb->len; +} + +static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, + const struct xfrm_policy *xp, + int dir, + u32 seq) +{ + struct xfrm_dump_info info; + struct sk_buff *skb; + int err; + + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!skb) + return ERR_PTR(-ENOMEM); + + info.in_skb = in_skb; + info.out_skb = skb; + info.nlmsg_seq = seq; + info.nlmsg_flags = 0; + + err = dump_one_policy(xp, dir, 0, &info); + if (err) { + kfree_skb(skb); + return ERR_PTR(err); + } + + return skb; +} + +static int xfrm_get_policy(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_policy *xp; + const struct xfrm_userpolicy_id *p; + u8 type = XFRM_POLICY_TYPE_MAIN; + int err; + struct km_event c; + int delete; + struct xfrm_mark m; + u32 mark = xfrm_mark_get(attrs, &m); + + p = nlmsg_data(nlh); + delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; + + err = xfrm_copy_from_user_policy_type(&type, attrs); + if (err) + return err; + + err = xfrm_verify_policy_dir(p->dir); + if (err) + return err; + + if (p->index) + xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); + else { + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; + struct xfrm_sec_ctx *ctx; + + err = xfrm_verify_sec_ctx_len(attrs); + if (err) + return err; + + ctx = NULL; + if (rt) { + struct xfrm_user_sec_ctx *uctx = nla_data(rt); + + err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL); + if (err) + return err; + } + xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, + ctx, delete, &err); + security_xfrm_policy_free(ctx); + } + if (xp == NULL) + return -ENOENT; + + if (!delete) { + struct sk_buff *resp_skb; + + resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err = PTR_ERR(resp_skb); + } else { + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, + NETLINK_CB(skb).portid); + } + } else { + xfrm_audit_policy_delete(xp, err ? 0 : 1, true); + + if (err != 0) + goto out; + + c.data.byid = p->index; + c.event = nlh->nlmsg_type; + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + km_policy_notify(xp, p->dir, &c); + } + +out: + xfrm_pol_put(xp); + if (delete && err == 0) + xfrm_garbage_collect(net); + return err; +} + +static int xfrm_add_pol_expire(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_policy *xp; + const struct xfrm_user_polexpire *up = nlmsg_data(nlh); + const struct xfrm_userpolicy_info *p = &up->pol; + u8 type = XFRM_POLICY_TYPE_MAIN; + int err = -ENOENT; + struct xfrm_mark m; + u32 mark = xfrm_mark_get(attrs, &m); + + err = xfrm_copy_from_user_policy_type(&type, attrs); + if (err) + return err; + + err = xfrm_verify_policy_dir(p->dir); + if (err) + return err; + + if (p->index) + xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); + else { + struct nlattr *rt = attrs[XFRMA_SEC_CTX]; + struct xfrm_sec_ctx *ctx; + + err = xfrm_verify_sec_ctx_len(attrs); + if (err) + return err; + + ctx = NULL; + if (rt) { + struct xfrm_user_sec_ctx *uctx = nla_data(rt); + + err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL); + if (err) + return err; + } + xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, + &p->sel, ctx, 0, &err); + security_xfrm_policy_free(ctx); + } + if (xp == NULL) + return -ENOENT; + + if (unlikely(xp->walk.dead)) + goto out; + + err = 0; + if (up->hard) { + xfrm_policy_delete(xp, p->dir); + xfrm_audit_policy_delete(xp, 1, true); + } + km_policy_expired(xp, p->dir, up->hard, nlh->nlmsg_pid); + +out: + xfrm_pol_put(xp); + return err; +} + +static int xfrm_add_sa_expire(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state *x; + int err; + const struct xfrm_user_expire *ue = nlmsg_data(nlh); + const struct xfrm_usersa_info *p = &ue->state; + struct xfrm_mark m; + u32 mark = xfrm_mark_get(attrs, &m); + + x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); + + err = -ENOENT; + if (x == NULL) + return err; + + spin_lock_bh(&x->lock); + err = -EINVAL; + if (x->km.state != XFRM_STATE_VALID) + goto out; + km_state_expired(x, ue->hard, nlh->nlmsg_pid); + + if (ue->hard) { + __xfrm_state_delete(x); + xfrm_audit_state_delete(x, 1, true); + } + err = 0; +out: + spin_unlock_bh(&x->lock); + xfrm_state_put(x); + return err; +} + +static int xfrm_add_acquire(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_policy *xp; + struct xfrm_user_tmpl *ut; + int i; + struct nlattr *rt = attrs[XFRMA_TMPL]; + struct xfrm_mark mark; + + const struct xfrm_user_acquire *ua = nlmsg_data(nlh); + struct xfrm_state *x = xfrm_state_alloc(net); + int err = -ENOMEM; + + if (!x) + goto nomem; + + xfrm_mark_get(attrs, &mark); + + err = xfrm_verify_newpolicy_info(&ua->policy); + if (err) + goto free_state; + + /* build an XP */ + xp = xfrm_policy_construct(net, &ua->policy, attrs, &err); + if (!xp) + goto free_state; + + memcpy(&x->id, &ua->id, sizeof(ua->id)); + memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); + memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); + xp->mark.m = x->mark.m = mark.m; + xp->mark.v = x->mark.v = mark.v; + ut = nla_data(rt); + /* extract the templates and for each call km_key */ + for (i = 0; i < xp->xfrm_nr; i++, ut++) { + struct xfrm_tmpl *t = &xp->xfrm_vec[i]; + memcpy(&x->id, &t->id, sizeof(x->id)); + x->props.mode = t->mode; + x->props.reqid = t->reqid; + x->props.family = ut->family; + t->aalgos = ua->aalgos; + t->ealgos = ua->ealgos; + t->calgos = ua->calgos; + err = km_query(x, t, xp); + + } + + kfree(x); + kfree(xp); + + return 0; + +free_state: + kfree(x); +nomem: + return err; +} + +static inline size_t xfrm_expire_msgsize(void) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) + + nla_total_size(sizeof(struct xfrm_mark)); +} + +static int build_expire(struct sk_buff *skb, + const struct xfrm_state *x, + const struct km_event *c) +{ + struct xfrm_user_expire *ue; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); + if (nlh == NULL) + return -EMSGSIZE; + + ue = nlmsg_data(nlh); + copy_to_user_state(x, &ue->state); + ue->hard = (c->data.hard != 0) ? 1 : 0; + + err = xfrm_mark_put(skb, &x->mark); + if (err) + return err; + + nlmsg_end(skb, nlh); + return 0; +} + +static int xfrm_exp_state_notify(const struct xfrm_state *x, + const struct km_event *c) +{ + struct net *net = xs_net(x); + struct sk_buff *skb; + + skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (build_expire(skb, x, c) < 0) { + kfree_skb(skb); + return -EMSGSIZE; + } + + return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); +} + +static int xfrm_notify_sa(const struct xfrm_state *x, const struct km_event *c) +{ + struct net *net = xs_net(x); + struct xfrm_usersa_info *p; + struct xfrm_usersa_id *id; + struct nlmsghdr *nlh; + struct sk_buff *skb; + int len = xfrm_sa_len(x); + int headlen, err; + + headlen = sizeof(*p); + if (c->event == XFRM_MSG_DELSA) { + len += nla_total_size(headlen); + headlen = sizeof(*id); + len += nla_total_size(sizeof(struct xfrm_mark)); + } + len += NLMSG_ALIGN(headlen); + + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0); + err = -EMSGSIZE; + if (nlh == NULL) + goto out_free_skb; + + p = nlmsg_data(nlh); + if (c->event == XFRM_MSG_DELSA) { + struct nlattr *attr; + + id = nlmsg_data(nlh); + memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); + id->spi = x->id.spi; + id->family = x->props.family; + id->proto = x->id.proto; + + attr = nla_reserve(skb, XFRMA_SA, sizeof(*p)); + err = -EMSGSIZE; + if (attr == NULL) + goto out_free_skb; + + p = nla_data(attr); + } + err = copy_to_user_state_extra(x, p, skb); + if (err) + goto out_free_skb; + + nlmsg_end(skb, nlh); + + return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA); + +out_free_skb: + kfree_skb(skb); + return err; +} + +static inline size_t xfrm_acquire_msgsize(const struct xfrm_state *x, + const struct xfrm_policy *xp) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) + + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) + + nla_total_size(sizeof(struct xfrm_mark)) + + nla_total_size(xfrm_user_sec_ctx_size(x->security)) + + userpolicy_type_attrsize(); +} + +static int build_acquire(struct sk_buff *skb, + struct xfrm_state *x, + const struct xfrm_tmpl *xt, + const struct xfrm_policy *xp) +{ + __u32 seq = xfrm_get_acqseq(); + struct xfrm_user_acquire *ua; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); + if (nlh == NULL) + return -EMSGSIZE; + + ua = nlmsg_data(nlh); + memcpy(&ua->id, &x->id, sizeof(ua->id)); + memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); + memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); + copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT); + ua->aalgos = xt->aalgos; + ua->ealgos = xt->ealgos; + ua->calgos = xt->calgos; + ua->seq = x->km.seq = seq; + + err = xfrm_copy_to_user_tmpl(xp, skb); + if (!err) + err = copy_to_user_state_sec_ctx(x, skb); + if (!err) + err = copy_to_user_policy_type(xp->type, skb); + if (!err) + err = xfrm_mark_put(skb, &xp->mark); + if (err) { + nlmsg_cancel(skb, nlh); + return err; + } + + nlmsg_end(skb, nlh); + return 0; +} + +static int xfrm_send_acquire(struct xfrm_state *x, + const struct xfrm_tmpl *xt, + const struct xfrm_policy *xp) +{ + struct net *net = xs_net(x); + struct sk_buff *skb; + + skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (build_acquire(skb, x, xt, xp) < 0) + BUG(); + + return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE); +} + +static inline size_t xfrm_polexpire_msgsize(const struct xfrm_policy *xp) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) + + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) + + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) + + nla_total_size(sizeof(struct xfrm_mark)) + + userpolicy_type_attrsize(); +} + +static int build_polexpire(struct sk_buff *skb, + const struct xfrm_policy *xp, + int dir, + const struct km_event *c) +{ + struct xfrm_user_polexpire *upe; + int hard = c->data.hard; + struct nlmsghdr *nlh; + int err; + + nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); + if (nlh == NULL) + return -EMSGSIZE; + + upe = nlmsg_data(nlh); + copy_to_user_policy(xp, &upe->pol, dir); + err = xfrm_copy_to_user_tmpl(xp, skb); + if (!err) + err = copy_to_user_sec_ctx(xp, skb); + if (!err) + err = copy_to_user_policy_type(xp->type, skb); + if (!err) + err = xfrm_mark_put(skb, &xp->mark); + if (err) { + nlmsg_cancel(skb, nlh); + return err; + } + upe->hard = !!hard; + + nlmsg_end(skb, nlh); + return 0; +} + +static int xfrm_exp_policy_notify(const struct xfrm_policy *xp, + int dir, + const struct km_event *c) +{ + struct net *net = xp_net(xp); + struct sk_buff *skb; + + skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (build_polexpire(skb, xp, dir, c) < 0) + BUG(); + + return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE); +} + +static int xfrm_notify_policy(const struct xfrm_policy *xp, + int dir, + const struct km_event *c) +{ + int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); + struct net *net = xp_net(xp); + struct xfrm_userpolicy_info *p; + struct xfrm_userpolicy_id *id; + struct nlmsghdr *nlh; + struct sk_buff *skb; + int headlen, err; + + headlen = sizeof(*p); + if (c->event == XFRM_MSG_DELPOLICY) { + len += nla_total_size(headlen); + headlen = sizeof(*id); + } + len += userpolicy_type_attrsize(); + len += nla_total_size(sizeof(struct xfrm_mark)); + len += NLMSG_ALIGN(headlen); + + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0); + err = -EMSGSIZE; + if (nlh == NULL) + goto out_free_skb; + + p = nlmsg_data(nlh); + if (c->event == XFRM_MSG_DELPOLICY) { + struct nlattr *attr; + + id = nlmsg_data(nlh); + memset(id, 0, sizeof(*id)); + id->dir = dir; + if (c->data.byid) + id->index = xp->index; + else + memcpy(&id->sel, &xp->selector, sizeof(id->sel)); + + attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); + err = -EMSGSIZE; + if (attr == NULL) + goto out_free_skb; + + p = nla_data(attr); + } + + copy_to_user_policy(xp, p, dir); + err = xfrm_copy_to_user_tmpl(xp, skb); + if (!err) + err = copy_to_user_policy_type(xp->type, skb); + if (!err) + err = xfrm_mark_put(skb, &xp->mark); + if (err) + goto out_free_skb; + + nlmsg_end(skb, nlh); + + return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY); + +out_free_skb: + kfree_skb(skb); + return err; +}