diff options
Diffstat (limited to 'share/examples')
283 files changed, 31642 insertions, 0 deletions
diff --git a/share/examples/BSD_daemon/FreeBSD.pfa b/share/examples/BSD_daemon/FreeBSD.pfa new file mode 100644 index 000000000000..bcd7c70aff63 --- /dev/null +++ b/share/examples/BSD_daemon/FreeBSD.pfa @@ -0,0 +1,32 @@ +%!PS-AdobeFont-1.0: (FreeBSD) 001.003 +%$FreeBSD$ +%Created by NRB Systems +10 dict begin +/FontInfo 9 dict dup begin +/version (001.003) readonly def +/FullName (FreeBSD Bold) readonly def +/FamilyName (FreeBSD) readonly def +/Weight (Bold) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -113 def +/UnderlineThickness 96 def +/Notice (Free font with FreeBSD.) readonly def +end readonly def +/FontName /FreeBSD def +/PaintType 0 def +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0] readonly def +/FontBBox {-167 -236 1410 963 }readonly def +/Encoding StandardEncoding def +currentdict end +currentfile eexec +f0f0f0f011ee838241a0cec525a60ce01562fd01753ef17c08b804c2190d1aa4d3d7a12f3062687674aa2a92cf8242c0f344f7c7ff68f4dfea2890ffb217b7cfa0dc6862b09b5ec7382b9d9919be8dfa2ad48e471b50ed4f50092fd1b56974c018419c73755c5dd5db8b4a67edc9172c690e4d9554f8e038edbdaeca3f244f0f3f6f82fe5413751afdc1ff2ef33bc43f20a9b5db88ca37c067e2579f6237b5a64aff20041d5aa4a925c9f299ba942510249706a455aeb0441beb17ff67c90c618b823b3b9293fe399139c747d6675013b85dd4d7d53e532028c93e07edc9c1735332b79106ae1f6f0a2a421d2a10dfe430cc505331f5285400bac5b960c568e46bc60424cc7556af3ab80eed5068afa949d01aefa15a3635553b4d965c83f5321a0bab542b3ad3f05ca5a4e80771ea7dac758b3fb0281cd6473439050c4f3e7885bcdef7ed3d9be1528d2c035f25cda0ff44ab6d715cfa66af54087cdcc7cbcc8e92b3336acffc0486603c1bed8575b54104fb7aa35a3468aa96e14575833f832bd9c8ac4b41547fd5611878fba5911a73e2d96ed3d59abef1f0a250f0cefcee604733a7f538e5cda3c343401c6ca1bcc4948dd1d4cd045021df7ea5210a5f251a26202a24a16b6ae59ea7ef139883199bd2a490557aa0c2390283e10c826084239c39f6ea1b1e72f374ef7a6ce53480ddb967b2b2324834fe0419ea2c384b5e78ca3cc603cd05e18747fa2ca764904b60244cedc0fa74e54798785f812417c1770b4957ec91a2a25409bdb6f0b0af166f49d28f9c0774a589ba28526bbd0f665c339dd6cdb25e642beb864e1662f9ace50434fb76cd5546a78f8194f802b0ea4ce5f70e3b3dc05f80449b6f10bd78e3fae5a72f5428080e27bc58bc9905b8484973d53e6a6a41e0ca8e436629e4f649775d7e8a0a88c81940e22e332300b9475c66f25369840e0f72cd01c070c8667d5c0f8c8112af0f1aa6db12206b0722787891641c1e727c2e87cc401fa57340ae78e592ad8e2bc3b53657faf641973565fbaf90a44eab3388c0600dbf26a8d3405ec28f0fb9b82a4d3542000663d09224b7796d5881643cfb04bbee1b1c42528bdb2050b07c5a069a38d9dccdede2403dcd9b4573f53c4b37bb400c5f8f09c48e0edf917b1b38ee8871f61f289a4953b529adc4a2215f25770d0a4a2042a0fa54aca3afc4e6d4160ab84621f15c186c054169bcda02740d0a75201a68dc12f774826fe6fecde716fae9aafecbe5a10d0a732027439113c180e348426805353eb7448230c4611b0d0a7420949fb81757802e694b71a36a3f4d7235720d0a20204bf97720c2077fd1f95f57638711e28c333fda3ef2715c3329fc0d0a6b206238bf6952f35dd90c1a82c221915394abc594c83725697b35e3fdb00e6d5249bfe459a56f9b92fa8f0d0a65204b9711ad986dcdad852ce1b3fee159a7bd1bc1b8d4d40f800d0a65209ca7a2e007d4c7baf438865a2e88246978e9b1770d0a7020c396208dc65cb425042298200de19882b5a30db439654e06b1190d0a2020711958391b2c7f46c3adfb6e97b42a679029d8912ad08cc15fbd810215967e4fd40d0a6520fc7afc363bd4fd6bebce2630021597309113785b7dc875a0e71958b00d0a7820cc40b6c2e94a5977ebae9525a0f64d98a0d0401ad315690d4b9f6d550fe60d0a61209db21491114b877e71a69d674a6ea17eb8110d0a6d20289e64fa978047f8bd11704c674e0adf52624a7974f93ead75fc26b7c15ee0ea5b9a3ff90d0a6920ca27e2872590202d9e6e099ea9facbc85ead0964f8b737d0db9a5dc7384f5cbc6d79fe0d0a6e206bcc41e1962873d6c7f74453c82f5f25f7b311683dfd6f145d930d0a69205b0bd00c62cb912b1ce63f83dc6331456da0aeb62bf9f89d2f003cecad652e6d0d0a6e20d5af618d1e41770b42b9a269a587593874c4b35e31e6f1e40c7f0d0a6720714b7e71ab6e47018b51ed68c2bd71e4c491c6c99ebde984af511ec5fe31379ae9ec40920f7e0d0a2020beb1bdde2adef7119a3e9eeea099a51232af8e99613b84d3efeb0ae280268130de65ac30e90d0a6520ea14ee07dbee79a7012a045ff72e07a6aada6252690d0a7620c755ad4338be2fd18651a9d59bcae5b796dd0d0a652034cddd542863a58c6206b1eeaef9ff6645372af3f12872a0d18df926b5c0e69337b68e1bbb0d0a7220edc4e7f756f1d3be73aba324ad4ccdce0cd13f54f0f6fa6cfd46a4849d900d0a79207c571000f99aa9868eadfca224c4256a7cec0d0a2020ceddbb7223bce0d304d061286369a7305c696ae58d19d8317b77dcb77f7619eedabeab560d0a6c208b55bb029cfc67ec7b00cd034d2f82c1d450a5ec384e9b78fa5a7a611d88f9a856e64b0d0a6f20d2f751deba1aeb0a213347487f00081a0c911f1eee6bb7537935a10f4d0d0a772078a005da145704f706e9b46496e6d4530e353e5270d5fa6599b8d532625a2d0d0a20206ef91fbfe46fcb9dcf84d90b96ed207bdde15164357c900c9724010d0a6220681e686171539643482a58049f71949a181fa5e76b01c282fe0d0a69204e253812773456c004e417b9df2607b03971671426567a6aaa2eff0d0a642096817660b4418060acb4d05c25dbf155221dc14f9c9d582ecc0d0a2020401b77185cfecda1a53e81c8846980ec5c1483030f68f5a508330d0a71200f91ce6d9bdea78b2dff4a307354bef1b3f1b828f05bf3cb50c3c6e5f571a5469cd4d86874f0d4020d0a75207e73563dc4e2094c7d30749f93af8ef33485035bd4c4788a6af06a0c0cbae60d0a6f209efdbc6cff3aca5f89463ef6d0cdd24db08ad0716603d80d0a74203c4d00ee3f42b3bb134b62fcd6ca9744270fbe2879fefac07d2da7decbd612e1931ec9198b0d0a6520617f2a7e967646965e5b1ff71f130c31ed8eee2707268900c878160d0a642044af9dd9b1a5673f929db0b130e9f217ed926d3c7739e2ee3d0d0a20204e6bafd2d4e82b074ad64010ef0d1a0c716b559a93ff1f34fd30c6a7ed4b0d0a6620c06cdf04a317aa801a46bca9e0ae096546ea03e3ed75650d0a6f2064675d5c812a37771bb20adcfa37c13eee756870a340c251373f0d0a722020f707cdac1ba6f97723db63fea574cbe1d268bc7ced3522a6031e0d0a20203e442d77f6f3317c610da752063cd81e9dfed1533d2d2e65e322d148dc010d177b13c552efa8389b1af013ebcbff2cf16df3f7322a8a210d0a7a2064aa30c077b23638ccb725d4ab0c34044dee581c375598b6c439a2e90bae42b9102a77305b0d0a6920a28fdc09e4ca1b0f9675755a34d5e82516c126b833389426702996af7158d205862f670d0a6e20238224b151c8f2a2fa481dfdf6327ee29107319d27f74411dbf04b2d213c0d0a63205808f3022b12a49af53e8860eaacba07e9ae56ab54d683c2409564bb0d0a202054832f18a697a20e14fa1570f35ac823df21a5eeba2f510fcbade4fbe09b0d0a6520236c97f67cb16f5ddfc1d597f36e8f834e7fcc4c523d9411aa8091d5b8840d0a74209b6858fe1699fd9be7654683a71df52411e11b9948e08a8d95120d0a63206f111b8a97eb1d4a853769204cb0e85e66c882c0aab0e95e2885e9683ecd0d0a682029e71b2021a94e5bdd6463981c89f3ecdc31ced1210b5f052cec0d0a6920bcb172b7c7994a2095cf040c623904f7532f2e9bac4f5d247ca12e0f53320d0a6e205dcd3a1e9e199c8d90d16426cc72060175b779f7de91ae16475d750d0a6720b62a0b4b00f7d31388b33cae14e14eca3dcf7dc05e387525a1cc57f5487d49230d0a7320775879199c3fe2b076be7853626f8ffe3b37117cd9df45307e3bd40d0a2e20fb4c5d75432834b6bd2a8470fc28d07872f48fed69c952c161e78d92b60d0a2020f30a96881a9f8578430ffe17198f61b19cb6c0d61eadf947422dc17116fb0d0a4a20705c2c50d222e0f0708be5292433ccdcc16facbc63298523e06a0d0a75209749d4125822a56a992e6f5ec0c552439fc2e9f2adb1ee82359d110d0a73207590a638f70ae3b506f1f32ad76bed42d978a47b6b18bf044389c3a82e0879c50d0a7420b985b62542b9d3e4407c96840957e36a27e1e0990a63dfed6d0d0a2020b2cfba0c9408786d9eecd33897a2efe1d3ce7310630d01c326dc041bfc4ef4c0e9650d0a6b20db3c72d9c54a158d0f1ca934928ed76911c7c46ceaf94cf4ba24fd9579482aba98160d0a6520415f99b810ce393c53f0576ccb3a9636b29e7b01a6e258d28d885ea9330568e486db0d0a6520b9e74020f8363590ddb460084a67efe6eab1bab95a33180b0aebe5cfe6f77353b0780d0a7020f729a94c445f285cf40dc3c8276325ce6eeba334e42e05c376cc230448c72fb8cd0f0d0a202036249a76565ab7b261fb1af10ac8db6380dd6d146116acef6302e40ad309b8f2973ab871820d0a65203c2af0303b49f5b8013486e63805c16af5cbe8b1a574bb0d0a782050069303613b18697460a67772278c68c7caa60c3a169ef902f42b299118f95ac90d0a6120375c5338d58fc253b045a426a8c15ae4cfe14d7ad4f72a7be90332536712c259fe6777d60d0a6d20cd106f121b002f9ee47af6b37f6befbcdc93093ac6516f43e6c280fdde30941fe8cbd37e0d0a6920cebeb84dc4505d5a811722b5af2d0609b888cf8adc8e402f8a7548ae2717694177f8fdd40d0a6e20d8cf4836f492ca7f8c8cfc43a6f6081ee0a2d9e59a4a3b90ee6ad37be7f2e2b0ad90ec600d0a692075dc3ce64ef0cb4913e9167fd54b8ecc37eaf5f56c8b079945873eddd60d0a6e206b037f2573baa6c8687aee0bd2fb6d547ed3d559049ed04c64151184db0d0a6720b419249d4614a01a57524e2b163ac9894c524d7abead0ad5e00b395fbe0d0a2020e72499b2b9ad2575c7429be917246d4c8c41d27cd8ffe37c47987a445a0d0a65202f4f07ee4d49d554f3e75180b0f8c99ea6e6074df497a0a78c628fb8104b5cbfb20ce20d0a7620d5ce376f1995cca71984202c6ff0d58f7b27354234dee2c2587b4f6fb4beff43a9e26c290d0a652044a84169c41a31436886ed52cefd2b2e09eef40671adf319aa50f05d76fc79eeddd98b550d0a72202a4ba5beb4aba03e5bd7dabef1e75cba34bb5739e1deff4db50714e34feb33ace1eb3e340d0a7920cab3c3192a3236c0265f1b2b02d50df6c80ca1c15a096749f478b3b69a5b56e8b4c75eb70d0a20205cbaab4ffda32a87348bf3d85f168ad49171edb42a4bc5d8ccbb2812e2699c9b20a80b440d0a6c20937dbc6457ad6302e87945148cf96df25b01c042c98a8f7c911b616de1c9280bdeb064bb5e0d0a6f2096153950a73c0dc0c9956c0046d8422a41a6d2305b2e4947877eb1f3ac4d8a8f26a262ae0e0d0a7720e6a03e3d2cae6fc6200e53a0d4d5c0b0940737aceb48e6f7656db91671360d0a2020a8e8be9c80d64a1c12f01f591763f16fe1d94057dc01a0e23fa20d0a6220c9c050dd5f91c2bdbc4c188092d603730e6a7b729380bef8aaed7ade46b227a0c18d0d0a6920ebbf9670981bbb142957ae40a1dec346201908a1cfc28178b036ac8106a2a6ff81dcf0f7022c0d0a642085a7defa9a767cde5e1b2e9b6b52f036404675bbee155e86f09efa9f768e20c425b7ee1d90b00d0a2020028887e96da15a4529efdb2e203788196ddb821f2d44f5afac1cc00f6cb39226bf15091c9b890d0a71209a592827dbb280c2cb90df58e318ac0a183f0f6ef54f5687ce3fbe72992d996ee766b490133d0d0a7520b8aeeb47e68d9e5edcbe7652c21f1a2e2960392a61656397f0fb0d9f6d1d84049b6e0c091a7a0d0a6f2024624a82df9ad6a43434dc7510d3aba86dcfb98dc8888051eda7c92639d3c027920d0a742039d54073eb456a2c3b4984d3ae8d72560247b4d041902fe70e9da0e045cb80270d0a6520ff501dc22e9344f07fc5f7f4a698f82fc1672593365bd95d620ca9436fd81908a37d12f2c862270d0a6420ef494b5976d137e30d5fffa04705f470f48236ef3e0ea8446be6f8bc46ad9f076493dad0dc4fc1e20d0a20201e3aea24f0ab348f8c0513078e0ff81937678bf61595b5efc3a96e559d73541805da9d82d32b76d80d0a66209f400278ddd1f549e7e55e24848252393f0e66eaad40a59afe302efdc971e3d23ffc0e262debd6430d0a6f20028595d51f8b68f2ef83ce2cc8900d6346957b84caa3790981f852daa01d0d0a722037a2a4b7b5f6560384c5ae4271ca953316830481497f215d5f584d1370dd0d0a2020b4cbb202c5a9606050b8e064a4db8f69d76c3bbb41ec4ce53ed9625ef5cc0d0a7a20a83eab5609873ca3614858f9fcf642b945a85944a0248f31839e4a5f752e0d0a69200dd663a24042f0a6a6618b7b3f1d4a55272712d7dee63c22ce05df489428421c0106de0d0a6e2070ac1208aaf2ebed0819e8cca4daf7d623eab02132ab246522eec2280d0a6320d670756672aa7826ca4b637d403806bcdf318e6fae0c263d604e0d0a202085e153ba77648acfdc241096ecbe085932da2d3f540a8f49487216d483d86ae791ee5762020d0a652057dbcfad9c4e6f45cb6aca49bfb8afe9ec89c1af2133a00a362456fc9034adaffb95c829ba0d0a7420a7d20fd33af595b94d5616ef95bc08cfaf8f2ced5734080b57e132599d7f1d39ecae014c260d0a63203e2864fc552f48c4cf532630fe186f67ed5fbe644c10a722a014371dc44607bc8b9476d0630d0a682090db3f64fcf979f22fbf341a53ba241fc311c95dfd27aec3abc7b173aca6d6269dcb0489100d0a692031709c8432a44e1f158fdbbe7b328d31e19e9357ad63f032ae8668dfba741f0d0a6e20488e0f642668a35505017f8190b7e53d1ff320ebf19bd44dfae5dc9a7404930d0a6720de728173e284bd4618d916a30ec7084a0282e85fe32f98480d0a7320ed2b5cf2e589a14f0b4d9316e882c1d449cb46ee4e8a5542a96df79ed2c0e70d0a2e20be7c05bd4057c32eb1770df804f83e7c0f58421a0c367b7bd67e5f88d8ab730d0a2020a7cddc1c77ce5d83ee6af31befb5c5f4ae737ed9ad6445d20d0a4a20d48e8e8a4659250cdb50be64b2c7f710232e7e9df8620a41dfbeaf485f34f8970d0a7520f8b5fe2a8f5264a3c3a397d74dbd95cb51be7ff107e4c4641db7ca0e55abacca0d0a7320077fde251da7ec82e1f5ce6a4a9d6548d87316170a909c01cf4bbe1260b6a5a40d0a7420925c5ceed7d521a7841d140ad73e199ee437fb9426b3e0b0da099434d7fe957deee67f726c9f052d0d0a2020332781d61f01f6e6874f88c6135b4aa8db2d6abfef53638c065ef056061afe58389ea9000334d2130d0a6b20dafd87cb69dda55ab7d32c1133f8e1545359fca44a65a4d2fbf20e0d0a6520ff4ae7a28a5ed011c877bb0b175ea87dd3836d107d823e3385aad19f4e0d0a652016054f393dbb34ff565e188a64d400ba670a5110d8770d968df2720730b79153b07236eaf2b2df72a23802616dfc31696051edf2a7e602d3b466dab1190cf5bf869e0ceff0280d0d0a5420f69e6b0a456124addb2cf41806cc9d8a1180cf082ed0990d0a68204292ebee557183698938fcaae5b83a1764c38e76e9e093bb6c5b04b4902c945c55df64937da01e133549bb496aa04191cd3a9d66bd71a5e2da79657af875ebf7508146f47789836cf1a823b63cf314c295799f11430287f9d6c72df4f75b35fe1821397770ecb7c62a28ea0d0a65208c4ea4caf3776d82c6fdec9eacfcc6e7ea62639d0f71d6298cf233f92930aaa0c6efa85ecd563ca9da6f24db43f71669fd2a9dc30cda309933b569369ac51fa462badf760d0a202045c24f0e039f0f6573d84589510a36a00cab6fa1282c09c905d0bed077bc783f4d42d00cccce6cc4516f621e28d70e50e21ab052891ad25eea6eeede07f82a3c71bdb3bd147aaab617a6773542bb247a89fa01717cd2754ebba640da94964d6c521ed65aa1e4d6b7d63a53f1fe0141fb5efa5b1a3700d9c78be08c5fa7a6457a913e07f51e686b59c1518071b79d58b46de5e1a6039ce3965ef4132ce90865160d0a6d2029c38412a72b52bfa82fdd33b56b4848735d96cae2eb409c2b7b58dfada1766b7068178dbcc71e9fd96877e02452e4b1f774da425bafe6f89b7ea5684f3a2905f2ca3c5d98ccc3891420f4ead0d985ef232b880fda400151d484d86b6e0ca41938e3455d14e797ab2a66060a0838f51d6025020d4414d939d13418f0951eca9802f11ab7da52ef7474f515bfe73f578edcc1ad33562d05b7cc11517fe238556b0809c9af560938dbed27b6ccf33ba4e3f973e53292c8742999b955e0c9d6102f0d0a61204d8d9924fca6d40b7b9c35b9adb0b41dc10a4f750a36f1fa13aa8bcc624d2bc0a6e391a2b8541f5976bd95dca3dcbdbf0c72af08cc632efa811bc7945ca6073cd236af52aef868bae1f521e0d0633f6e813b59ed2479a8b9d748ccdab92cd5f92f1ceef0e96d6b84f4593168b750b73dafd419d087c62355bad1965be357d8bfc5275ebf360565a8edfcaf28e26ed7605b146a27d4594ef8f6f66e1e146679f484b4e3a40faeb10893db86c810a62dc3241612720e49edc5de5257780d0a69200b2379c14c4a8ae0c4a18aeaf1394b6fb6beae15d7ced918e24632482c9ce8a6a2b3b5c93b75fb3f66995a865d1445473dae7f6b6c500bb3bc48fd5cb02f2e9057005c82d1fe9faf70c51d2f994102ed725ab12512dd159ff947cd7113f2b048a6aecc846a3b2f43ff4c0b9e0fef72026196e3beffd11aa00922aed7e4567d22326a8a42c915aec64c85846f624dd227908d5b51d60c2f07dd720d4bceae7241729ed797b9bdb3c6f49058c1713612886def731a2e3c8e024705707937a19bcbf4f19e6cbab387f03ea32be529afb285706aca103a0d0a6e2052d47eeb2892d03c2a271f5c0653c010fa4e0188739295b39b2dc4ff05414f68068c109a988a506ecd91b4e9212797bb0d0a2020501ec10488391a2f7579465405dfca54b3c9e017ceeb6a3b12c25bd198afdbe88409e807df692d5955dab71b044fa8e9137e62ba4b7bfd9b2eeca5afe3f9ad28246b74b006ab41f590365155dd41c0656c4a4c8a50837b2d55996f60a11b850d0a61205b433512163a92c04c0012c2062ce734bca8dfc56096f34fe215786e28b897423a24dd6c3ab9550140c814b1c1ebb1b208c6d5c37e6888546af8cbe0f6b968c2c12dcff5404f8760614189fb731d55a89c2e7c1f24d16e4f4cb1a11235280d0a6420b2535c884be264b645c6c83af14749bf58372d5eec3a10f2e9f84ffd8f130ec429cc0f0d68309a771e9846f8ee78bb586c6478064d65155458a77d9bb8e6b75a727c9fa109955da6541950d1cd79873879acc79879266f64aba43f5a5d5e9cfc69bc400e173e206c33b1f206112701c57326d1e79def9c03f80d0a7620fa1fd7dfe04cb709fc4da7e35032e4d32db2140c8caddbc28c8498d840bab6b47c42ed8141a599bd95e5d19e5c94a959b1f17faefeac50f09952306fedd5a197d9990dd9b40d0a6120a6a313f738bddc30c0a1b117153f685258a87b83c798b5758ad94d4b2165da94ace23605ec7e5fa7341c50d3987226b7d5b66932ac28af6569c64b9cb8c495d2c5a00218cb9944962e0d0a6e202320bf2038fd3a186b6724f4dd1d5f6a3d592c00e70cd24a999c15703c9f52d0bd8b613428376e16f86d69541a27d6670d0a7420ff870c92b8e58e12f8bb83fdcc2984eb7c339c19145c5fbbf002386dd3f65f81254f31fb8635578b79266b08391191249c93e2ceac0d0a61209be4f9b198830b431b2657b211b470e2c5c869f2af5dec7363279024ed7795a7fa93f25d8aebc395dd3178b30ec3f00013bf0d0a6720f2fe0b0e82b8731889a4f1574470989c6125e932e1a6617045b6b36a4555136d32e389301b6a31d04c4ce58c83dbc881f70376b66ba213afd65e609a3e2985907e7ec38cd42fe431f84e2473492ee38d9331101cdf9f58cf7066413059cae726ea13e021ed660d0a6520e2e86c939cc58cbdc7f45f5597d1efa2a17587d06c95bcfa96d2ee0a0d72f0c7b9a6b45eee1da7cd1319bf8471d2e90d0a7320ff3bbf9a4d7ed10415a353c252e8a762687439500b2d13c0b0c7d04934332404163b1d89264f340bf1ba2f6adc50f8e5aa2c6a9c3fcf2bb2a55ec888ca10b8931b782eefc957c86b33ed68854ce4265f1ddcf2123c6109450ae17f5038d88531ff601db30d0a20202f95dfca5f7e4b8854fe2227100e2b91e80595dc147e8e095e9adf380fdc70e240e90fd7fa27c62c9e0b386ab458dcf4fce9197f6c22ebb1c342397e0eba1f82bd23b8ffc7e1d468e5dfd664b455dd2dc468b04c787dc725f11d29a41db99d8c003f873c01bc463b8b515298f3840d9299a5b257c2e35bf1bbd995cf004b54ecab22a41552c07117d70d0a6f2011b08bdaed6101ef6d0541d189e0ed88d188840db164d9e58e464ed904970ca81fb89b401a5ae830ec595bd7ad8f13e7a9400e3730ee72b8a5748ba72a090780fde5cbcee46b1c20d93190e51e4936514aa12b2f6086180f110d0a662053aa125db3464ae890fbd4843177c43d93460be33a42bedd50b214f6cb4371176c86209fdc3b9795e74f3b350389538db53c8a908db5ac0d6293752e80d49e935ee8dee4bdb66dbf2d844cb22f62451d3ce669e2623bc7e3a039aeea8cfc86f9169721f6929b6346ae14336abd78841c182d26e160e65d0d0a2020bfbc006e4f845c4f2fcf482e4b28e09fd20e2fee0855d6f6448d9362fcd8f896c8d7badda6d5551f3beea144619b5114fcd127b90a6c348bff10f5a0d7989ddcadf40211557114da12d742bff155ae56c0374ee92d2a1f5ae0e61c9f74fc7c62915b1d289687b6be28ac3ff81275ad56ec080520642f310ca9d8fde025a33ddb021a40b44a0d0a6120d5eb639120cb3b060782a0e95b5fea2d7354d6ffa0044df25a0b7e1ffc5693a2b472c762937b12ed5a93a61557afd2f75d43bff12f88801b23ba424ace821d0d0a202050084cf2ab7a590434882bc714cbc1d254175c60ee807f4b80302a948a720bb787d8d82c7747e6420a84e0fa62cc528a70c182802d293c3872275559661852b533e336805a0ddbd98ea554188eb529d2395641fe1c6ddd9fa9076e0fb3b91b8bc6a0457f05ac678ef32d24d6fac7461aca7d3a32f65457c34395a93fc87dc1b4336007f60e264400e76a93154928b65a6698f824d9eb596061fb1e5ffbdf2a5b52e3fcdd84cd735ef7591691d2db518d010d0a6420276acc70e256104396fe961964d62830e6aaee75da7ae9a71e26a264c26df317644afc91920d46b146bbe440e7db0dc7bcac65a5c16ace7a7ff23e37045b36f9d83d6a46457c4b30f5d365a274e35aad051873138ef50861d18c2d9eb5fb294f3a85d2c2b483e7557cb2b7f2f7ffbd4a651b5cddd277ec66f5404e87c2fad4e8c442f9c4c00d0a6920ab28736f70f02d27ee108fe3e752c846dfec15ee4e8d7b73278d96141f625dd76f0fc148ef06f9b4ae4ed971a255dcf8ecf0260a64586d781b25836a620dddf7817a773dd8484f7263564c48b091ffaf9d7f52e1c1d20d0a6720729021fa1722d3b929b88b76b787577c4eb52e5f704649053763dbbea06cb0036a0cc70514ebcbbb4a595380f7ab7a8211ed0cb3430a1230d896e0219fe9087d0c6c5e94da4bba82ddbd012291bcfd1b3f8f9dbd85a0a646952d24a64dc1ec3d0cc1cfcf0d0a6920b562ff2484e0f03dc0754dcbd4ad92cabcb3056ea49b639a76df7fe06dd4d8d20236b7001d9b398ee5e96627d39e45f8cf29b2a4721e50880de18af3871a6801020d0a7420ba5afa2d563accb973b7b5b5e9dbec290678a21ad7a75f13ed0e1089f129cd4b788f262242c703df0f7dcc6748404647e026411143e8f08d0ad5742c7941a9c9a40d0a6120ed61c4724be086144cd4394127879f18f6c3ae2a1517a18745a567d4df32a9fa0abb2d2377b69cda25eedc22bce867e7332502658cb298e481b7ddbff2f32ee884540d0a6c20afc1d7dcb2a7473bf006ac50f8788def7d188ff00c9e0360baa6245d73ad42db74a2706558bea5733707a718cd550c38d4c5dbc4c39543ad5bb1e1a58d5049d551a5c11279ec0d0ad893162ac5c51a74c2aa410f25b3feec0dfce33dc9366ffd3c4f47f6bcb8195bab6a4212b9532f973dee1d720a6f390478167d3bfa8601960fe0f453e08cfbf00d0a202038f7859cb5cc0bb441658695df18d5109589d4423e0ef71a00be32ca90fc255197848065d87c566caa01446bb4f4c65a523f8fec878f72106d9505800c028818bc0c099f9f1755728a3a29ae6b7371b21011d5ac6a0e2ed6a4ee5a559433f9ccbe300d2eb0dd3a9fa602d5a7726ab1df0b917ab399829469938d98bd0cc0d3e82a6c898d61e5a67b04abc2e324031738db2280727242a1a3d8b383743a3da83d94e1a5a14a8ffb4386d900be9868150b1f528f0002b8006f20423ce5b2c6aca801a8507322e5171dd9d3996f6f88275306f6706b70f210f45fa76043ba1af53f0e09f28e77d2db6aa1aaade541611bf9d1b612c89cf9a529e48f9229f850735c542f414c388d54f605ecc00b582f30c6df0d0a64207918079bd8033c5c6d88858dc110c6ddcdc4d515f9961c1a9f54a5b653eb1b4640b5cc2a7af730f4db53be1f8ecaa4d7c992cfa79172f8601625a79ca7ca309593bae51037ce07ce87044bd4c152414be99bb4116c0d0a6120c926c4b086ef2dff3c38b15ea858c758ae3dd38dea8d1fac44270fa7354ccf2708f2b8ec1d9a93f446e64c466f371aea6cf60c298a0a5bb4c888b01d33b6d4b2ac7508ae2c591ed624618151d589436777c19183f0e95abfd92c927a266e4757764568d716826d2c6a7d260ebb3ce4817f7c5020596ef54469a6a42fbb0d5046d4a333a00a763d99e2ee37965b3505ddbe0d0a74208e29ab773e3d625ec81ab4acd1b46a6a7cadd8d6ffa6660895bc825f8594063e5ca6bbb33eeb90698c3ce1d826b81fd361f6e6616c516fc8966cbc0134dce50bffd9503438bf81328704d9ad1c884ed223bb8f790c8393f978aa69c291e5035c9d9aa548772a8d012b7f858600c70d0a6120d50c8e685776c6c46f551900090a66a26ca0d1daf761ac6b96215dcc4d850c134d2fcd13f500f9e22a4695bc8d819ae8ee078dc70d42a2b6d10b5e2d92474ebfac22748d49f59ebeea6928cba19942cd1cc85a57b146ebdc50cb1c2a778ec08d314e94e90c2701c4ccd931490d0a2020c9398326471525c772bd912fe207caa074ee330f83c1e6f76290c70a98b29ea35b49b743dfb6ca74a31d65c4c42b0fbff46027941542885b22ca577e65238bb91c663c55e74007df616fa00d0a7320158b710b661e877329726b8c71527e3e28e52bf13f2e25f176ab5bc34f228ca4ed007c8c80adb5b4aaa80868cc3bd07132b4e88d15fa6e26c6b26e3d73753447accf34c3400d0a742048f70c877e5040fa8798518637ba040cc17effe536ca576cf71f7ed2f69365a980052d57772af07d48c551fc328729e8b5764a9331eeaea9d562c09b2f709fc372eaac3a874c9b4a9869f865ffd6b094147ff1214e3f7111ff408dd4eef6b28b3eafc5b5289083341a0b8987ff0e527ee7487a95ab3800ccf3efb2be480bb726d61e550d0a722062cc68235cb0ccb2103491922cf5cf1198c62fabb39507932ce4adc3bb98e129616027b7d7a562d6a89605c7fec45423515211da7426abcadef59c16cef33215a2ae407623b1969597bc310080cd0d0a652052946808d22f61742b7f8f277dcac79c497e655f8512203f56f054bc0db2e642ad43a1385c717099d9ec60160d0a612075862a576494ff79ba653eec778ad0cf0cb071ed87b7acbafea90c113536a3cca3c99f8b17c997960a5c8defda1d972cd21b46e554f96bad17cc22f42736a00d0a6d200184707d3aa2901b59336c71276dbbd599db6d5b3a4849300cfed57cf370be84c240114e1ec05d620a6b8e98942985575e0f5bf27a1b904f9b99a40d875e1797d1f3e54c13ef1b88970d0a20204956b8172c834398f56760c11531331fb876a0f1a5a3e3bd29a76bc26a16370d8deb3ad404c404544e752b046f2a4787386ccd0d0a6120a99b45f0f43139aa5e003337b4d211e0840b57fd4af34474247494dd02f8441d6c7ada218bc380450b3fb9abf5dcaeb4613eba492ab55d854a165027f6ff35ef7446d5a886605d57fd7987993422a5eaa00d0a722024bfde2ccbad9d06af42a88a77bb97c490d4ea880c9284b014f9ccb55a442c301b42abf2878780cef0096d021c323273f9ca91da60549e8a93f99b12b20c578f7250d29a545c674a73b8b7860d0a652032bcb294bb63f24cf1e31bb163ebc4cdaea3586a2d915e9502d732c25c2fe738c4456c77d1f4530c1613bd7595d3583bc971731c39d0924d7887ea75ec4848e49fa8afe410ff02e9f751ef1234b3414b0f8a4aab4ab6859418b0c6919109fc8a8583ac1b89afa01ab6536b9cb3a5fe37b8bd930fc34365580fe15e73d81df053016cbc620d0a202021fadd888abb83894fbb84707e333a6af2447302c3ace25d1eb8cc379a705ba8add551815117bd632983bd4f43c694768e661da35e88c29c688445c91652c1d9ffaa9f3658df567332c7c531a0074a56ee635c74a8e1db9fea90af489f03f90d0a63208488f03d3eb6c514fa3d94066ab684f260cca5506f4d7f99c599536bb5c242f38ed97f209c1b52845872249d80e337c73dec051137bf0e2741a4d4a4af4dd387d22d69e2f7cc1cc91f6ba1d334b8a8923c67491d69f60460c8b0791a314fa5dfc25c1b54c031095a8234b36589d0a7ad317952f78857cf2323e7cd53ff61dac3e7d8a00bd9e6c3333009e22da75410121a62c9945e91655bda6dd76eb1acc00d0a6c200415be4058093de9aa2316cceed4e1e31f33b352df0f3a5665e4b82a18ed60711eeb3a0ca53a942ace3aaafaee9ec442cd4549c0779dbb354a10c3882bed259c749b268e7028d21fbc13bf9464541edd8d7c960617303c1648dc28e63e665a6671885a136b67fdf2ba67f3a50e806d9a53f0ccbb7f7225aaad5838f4d4f30d0a61207e720f01fc9c5f0fa38d35a1063bfd5127fb36de943cc5d0e3cbcd3d617ba56369e49f49bb240cd65bd20894e7bc3115035a2009f5d3ac1efef14a4ba758d2f78854eb2ae878a4c8be93583f800f49238ce507c75d51a708ab4484f765ba416571abc98fb038e03556aa19cb30ccaf803ae0332eef25df23eb4306452a4e92ef530b4968ab7e1f3b0d0a7220cb744f6b008094d69881af23c7e33d3506a3405a20487d17aa51a679cf734f91aea14a5a7c1a0337878dc28d06130f795d52822f715d5986f0126a0d0a692024f94ea80b80b9fbc33778f8bc82cb60a5c6892edb8102041ab3ea236692e1583709f096f18a4a1e8e8e534ba1c1908a5ccdfb588e080a239212eeff33ca0763a0183be73ea3d8bb9d62303e7bf49fbf593d719863f52d09cd85a90d0a74208d3ebe4fddd8dd9979094c906c85a5a96cb240e5be6c36a9e3de5768c0dbede0707ad6ea1df5c8f907f1d65982a3b9b8d1c20ac781c2f9198dcee68bfa77530d0a79200c3ab52318b338558f737e0a14283d4a08c2c0e9745f46cb57f1d7e68057543175dbeccaab8de82a8983fc48231a97f761edff290046a58dcfa5b78d912702778b6300954f5500f2544c48654170300f82be7254dc152b2c0d0a2c2031804cffee53e36ef173067f30170bf95a73096321d91ff86b303303b8875394d480710dbf8269e74adb8830380c53aea2caa50039b6a3cbc10bfaed05bd67b186d9c3ebcdcb619a571c6504ac3b2a29439fdc8f0d0a2020c6699929db1bb745c643eff9f51e8f65ec5f211c70e713228df39295dbe2ca9c2efecaab338d77095a081ace85fc72cb444e8e0d9fc1ae30fab92dcef43e8445f108eddb1b0d0a7220ecf1826f5d96c901c62726d9e141eeff8a2a410dab110a6286aaa706a5f53ec1f0168d69f3e6168ca9527cd3f2068abb5138c96540981bfde3a2581e7fd2e2b273241e2f44b4d6e40d0a6520d00509576abd328e2e715698997ab82b6070fbc94ce9d17921d57ad65684f5bdff26ff0d7e10b3a9728c3588f2d7f4975d83d852133b1dbc21ce46c9a1085d6e805a23070d0a6120ae79995e1ca0a1a0008d34a50b9f28bbb37ec71b32bce14bb0af83a919abe1fafb54c24e42800b8046e13f909ea588a3336a296cd7171bd9aa0d0a642017ea3593bcd590f325779a69e597a4c7ab9b8030ee4714578470a4b7085e8dbae56031b94cef069855a3a4b86d5965ac1e1f1fd81c9d481e3cddeaaf1d3e2d2a12b39e0de7417f26090d0a61202ad7433c150e0613d7d5067ca205502505663f5bf781037e42ea9c649962225173bb20819df4b984205ad6359ce4d7e7937c4a1fae3859a5c13decdff428a794800fb0fdec62467e0d0a6220ce16e26b0aad61c694c26178a2cc086c249b609595ac2834233cb27e92c9c7146f44ca4e557533bf99ca64a80d0a69200202da67e274a694c6202b46d601e79ed784bfa7c3d068ba44d23a6c4821d659e9346760c73cc2a8bd502ebb6b3274d5cd2d0d0a6c20e87a875e9e430ca30e536d2db39f665f9b07cfcfb7a64456e7c72c5bc49893fe86a29be8ff769cdc0d1f8dc1a366fc407ba65d1222e6d4e316d853c02770d2e7a7d71204827690429c0facd704145d445206b597a503c4c77181e2e05d82b92b2d9f7fadd14af71ffa2eb684eac3b6596e30c9e9a5d855a6d66ff074651ca4d411ea97756338e5f7171a12497fc9b5e023a88723fd17fae998be0ddbd3960d0a69201048b3cc3544e7ac0fc23ecb356de1a4369050c5f0e0b20b127fa3cfd99e4f64ba775987a6c5aba8cf032ec1dda95ef0758f81e5b4c19e252285b62b89e4077c033a90fd5cadb5d9515de054d94a941d8cbe15d8ba19b7ee99c7f21ce7d080e010aa7ea3590a0b19320e0eb3ee52466d0d0a74201c64f425bb2169df311a2f5597270edf99ca9649e0e7b309d11a30647342f61aaf5293858da0bf69b3279470faf7267088b9914ce3dfe9b24eb9196f0f18cc91b9c3559555c48510971ffe8a7b8ef129a01829d8dce55afd03b470e6ab06e89b0d0a79209083a1c2bdf8e16aa3165c310cfbbecaf18b5fa1eba09f16cc06358001374bb3b3ee06af037d43421e99a19d33ba4088ba999c8cd207a74c737bf32490902b7730ce78b4ca848dc2534277781312298eb0e2f2887747195363b57fb951429bcd95888ffce4359a5cb9ae6a8b7ecd6ee67a4935974ced934d36d52333553cd08c3570c3f68c1da63a495464ebdb1f0d0a202003e91a62346717298bff3cbdf1ecc18a9e53867aeb9b9f19106fc20b843836e419e299f98a3c9ce0d93084d90d7aa8cdc81fa25766a17b659aa2e52985ab19c99322483d840c04d6c2d029195c235af6fe0771e7df0899b84968a861e0f150fd62b31f02a8891464fb126177223c0c93b27d15d6c70d0a6120252fbc5de63dc9375766a4b2073005eadf1995705bfb3d7de706ce838e1540ebb4a25c989990f0b41ffa7909f10fe3e0d90f99082543bd7341d812a413a6bd015bf2ca372f9070f5e18d7e009847e3cf514bc9abefb147567c2703370d0a6e2020a8d4ac234409caa1c9d598dd328e229bd10365903a7504cd8997b23dcd06e503468ef2115e7ba397ddcc82ad81d267a8ed08ca80ca7b7b3cc1a3f4ca12d572d9e4a32c2ad17550efd3ce38e840bf1dd736c25bbf8ae87dad30018040bf4bc6575b26b2775b28d7d722d5f293bc856cfd437bcec2023907e8dba2f02ae69261ecc065397d1768acfea754bd351e55d3cbf3cd3b76271636e173359da81b0aa4e7b1716e2321c49a800ee30a3537533cec680c3030292128152da97e2c9757834c1c04fb21152fe267803685abca8839bd9b5dc81527b90d0a642088b4640b8a707a89ac671452912fbe5cab38fd866fc1fceea9232f739bdc46eb3123fde09cf62d45c8bafebed615057d1d6c74eaa8ff08e2bc7da50dd88462e13986493974fbb6446ea692e364208675f8f2ab161c73469dd7f60d0a2020fdd0622da8333890bcfad4720eed78eac5861fbcf77b270595c1e30d49d86599910d7fc96a369a14ec23aa1ea6c4f6431175fe792ee93e48f6c279dc3aa3152113b0c16134872cb1c1a7e9460d0a652096e05b928c62d916ace0271d7328a119fe165496ca0cfb3ed544864093cfcd48e53ad5c2ebfd70fa4dc9269f2087a43052f2e93fb122d9d4fc0dad4e6c98c8bc9d40831497b059fbc98b9fb37314ab6589c45a4edab176f362cc6ce5caa30d0a61201b2067c0706ade699715ae36027e3812c721b10a3c54d05af56f6f6c9136e8cab69b1d268649baa4f97ed3cea1ae8b96400d797cb9e391931189c607a9f653b10058773a3c4a7f4ba5af600c4ded0d0a7320080bbef2729d0dd4bdaca4c6f133545062f55e3abd13c04924dcd0614e7bdd1c99eac038a1f0ae7fa0789b74a80d0a652025a9ba65e4484c4ca9261b30a5d0d2c9581ecde45ee60fe6819920556e46d449d281acf686d4bf3ee16091d3b3d5e4dbe82307044006938d43b84e4bdfa4c8746e1ad97dcc9ae61c95b3bbb47fc4ccd06ee15c04f0091998b1a176d8c8181a435b05465469d4d1334aa28af892d28569afe26c02228a52a59a0bed56d76c87446fe27139d732d993e487df38e40d0a20205d1c4ae4d90b7576d6f5dfd6cf58a2b23aba655c320cf8ab28506e3b0277f054cd77ef6540b5f09bfe59e8a52d4c2432db40b23dd93b506c897249f08488994985b720eeb7458e268366eeb89b2f9c7b457a80cc99b0c91788c3712579e04b874eff0f41bf0d0a6f20cecf59d0237445adef1e61090a1c63533780e25f252998333986c0a7f44eb262c7767f28fc41a51856b360e724973c3f0a8c70b4c24e6933eecb17240a1ca579e803391ccd01a304c17595e27df95a8251d1a57a467ea7eb1ea6117d660d0a66202dedf71f7a6457cca206d9d9f8198119acaedc29a521ea4a25509ac49ebb93cb17ed252097ea4083a01907175923d0616bcbd57f31fed51c0b68534f06840707265caf28798a70fb9f8eb82bb703ebdcceaa210eacacb6f847bcfd1420ee66a87a8c251e00dec80ea4183c1cbb14a430a97fcc6f45cd091d9e76b4bedb4660c476c8748a150cef520d0a2020687b4b93f6c1a7361ae79e082698197fe451fcb7c3e08b7cd645b82a8b7d2464e29a69f95b476c92fabf4b9aecf1a305dd94b90d1fc71b1632506572eb2a7209ea4b10fb3e55ef63f79b947980d02cc219de590e0f1d171a88cfdaa8213868cdeafb6b2c7dc5f8974c8039fc841ae34de1108966a0a6f33273018d307d81ccb3e650509fb60d0a752068e1658613d75b5c49086484aa8f476276daa4cf09ca2d2eec45a333340cd3a3aa712ef4b4e82de51e1aeeb207687a3aec203dc2af65e610010038ba92579ac4c61f36e3e5d3a914ff6befce08ad736486b87501b6f0b5d4d9669da9e829bdf6220d0a6e206c46d50506eac42ad6b3196d0d0e04ab75df8bb59984fdede47f75cb94a96497502a7ab6ce82175b56598bf7ebdef99680eeebee4c9cbd9cd1dbc1ba6f682ac8891d84d068453dd95a32d1f8ee714e9fe588890687ee061ae65cdbff7e8bb6947c8e63c5376e8e0673c7a5aa9e5315c952610a32a7ffe6e3260d0a642086a9ad508b454d43295a12c340b3839c5c19061fd89e245acd14492ad55df9f27214907a5a2fba2932fa1023ee8fe2edef76c89642ee24aaf2e9048039eaafb17e549de90586848ae39ba3095c9e75583b1a45fd8cbd46606be46e7e210d0a6520d5cbc5f346e18c96491593531b24894075e56e80a05ecfebe0d1d35dcc0c587a4dd451b73d9740ecd10794be5b371ea9d23639fd756bc7578c064e73bda35d2faf544cc3602f0071ae637bf000b73b28e36127465780f78de0c9d9e247864b66c94e840d0a7220b383911d102ca8b133cf60788955143b1a22ba5cd4aeadac73f40776e5e8543138db4f5b0c59e9d5896d12f8c1a139f0ddaa8c4536d66274c55d5519590d0a73205c7f46b8618dc52191ccd43a56ec9cbfbb35345acc94b172c888d79b7b967bb9ab7df03f7f2242a6670b50fbc8ffb4270b772978ecdfb6554242b34d13295aa433dccf35ceb9ae1bcfcb9b0eb701393cf2c2f4870d0a74205e256914c56201bade90466be9a34e8fb97025e744f29e9f661029af0037ec83208571ae9d13c9666cda67692fa88a5d89ecc934e346760f96b9f081b03a8134980e6a60761224df65b7944e538eefba0d0a6120157b667be8e539a57b7a29dad22480022634a628d5bc33d6bf91186ee569af513cf20228187ebdea378e780498e0e0f4d6f632c7c0b0e57910d0c955653de703e65b9ba0d70d0a6e2010dd198922365136f8c873a18a504077cc2c5ec6448c8f5bdc89907f0df22ac6375c84fd07936a02032874ef78bda9c29706131e1bacecadf889139a98965a7b787b492b50f8b70d0a6420b792faa3ff43a09849069c6a22dcf047b34f696e790483a88b0ca602b91ebb172a1ec56c4a3aef090a58f5859fc5a4c91fa7d9eccf7a228fa6899a17572e3d6e1db1ed51ed018529f94e28e26ee194896d95b52776f228fa59c1365999c6d33fe3d2ecc5f9b96545f2d869e63d599548142d565612c06a49e0c9a568a49abb22825038add6260e8d97dd80cc6717e59700f038be4afc7970b5ed765cb1efee6579755c4cbd0d0a692028ff62d0979d36cdad5432ef66900a6ae16c5cb3d91191ec142d36f8c4fb51ddc1b3700f249ce50a6a85e3f1f15f986de69c6e87ae9b0d0a6e20a46063cc6f01188ac466ae7495560199061bc621b53ff30c321c28c14874f7f796a2913ae36b7ddba7bf759419b3cebfea71bc8ad5bb9d65b9ba06c21400f844172300c8dad123fad55fa64809e61ce05b22b51a7f4467bc55eab3e7f958730a2bb6c04af4a49f606faf0aca8ecaf4fb9cf1c85c0fd99e8b53671f0ed8f78d95b933b496e930bf9e314a38fad611ea418007326b537de3ea7d316a8893950d0a6720a6aa83643d6fc8e800d7c94cf2783123de5fbb187ce581a87d1a357b9aaa94641df0334d28fc54dada438913ce69e7da968e5f4ac240b6e915a907d770b3118a9ffb18bb5a5edd39b31e6f27732a3b1556daee5fca110ac3436116483f31e5dc4d59aad60120fb9e20e21159ae626c1b0f87025e6e64360d0a2e202df8d388f4a98eda8dfd74c40b4ae1b3573bf1eab3b9ec161c7d2d5f25ebfd6abcfe0033832779c8439d4b64e0d3f2cbf5731a635a9d551347d1520c3df31a4442581337f5271267beed0d0a20201e444f2e6ae5c5a075fec3e0fcae8a87953265037502055a972bfa716206514b4e1a37e80976d4f60ccd4a2745ae98a239967b7fc52c70048133086b3316f4da819e44e0ea68afdb291951f14d5b33c0d0170727f2592319cce3e0069a5cf1eddf898a40188993833306282e7a357efe033b04d55e0d3992262d48a20be64483c333865ad7329c19c62e49f19caaa37c0d0a4c202feded620f8653b2d06c9b816dd80518c9d1dce1cbcc0875f928821471fee26472ad6cc2ae2a4b75f05dfae4a9654f1625301fbb2784d9080e85c7448551cc1ade66fd97329581f9e1b36fe1287cdeee645f87e416901062cea4e3bdb042f5d9c17a0e511b66f378fa3dccf3f809d5dad2164d00ab271cc20d0a692069f06059fa598ea32d104e014219ae8ccc3e14788fb79b35dcfff963df6ed228fbe22f4573b6f042c55497d70b7e90c1bc6d610fabdb83e0e53f1626815884f580dce278024a6ca81d62598e947e6bed51bd41764462a14441046d4fc436cd44f9fc3c0d4cd9af41ae7e7239cd79e139640d0a6b20202a6ff2bbb3241e3ff1199145a803f734acacf1c0cf3394b2a3f7349ff46d37e16248d5048fee5f26a4386e7fba4f35df18a431be05ebcccc89b16c310acde47f9b2541a380b6adcac07f02d539d76bb1fa56cb34482caf857bf97a9c53de2c383b0d0a6520b68f0dfb8f8f5c401b8fcc5c2533cf7f926f63a7785ab6f1e52de7a92667da9e4cb5162b2234469e2cd77427e9421d0b5ce3d90a545765a8662bd1ff043743234ffeb36d50f0e46d9d9095bc69bfb66b3f091c88b443da23a9c6ec36d021c55e2e48e0ccc9f10bea5c0d831b3ca20b7c6051346e7015ed7bbec794854b63b1511b4e7617c734cb9d91854cfd0d0a20204ed12678159bb0e870122a76c4694a76a913a56eb23cb21ad2f6283f52953356903c5ff32430042ffb50ac84674c52937dc7a3aff7a588ac830b9c9432af0d0a7420f3e9ada42cc8665f85fce50b09b94da70b38e887b26026c9dee1615529519bc4379b404bb94e2b10bdd1502a861bca1c39a838ef4674d9ae3f65171ee93b9510baa05546ae773584205f60589a5ca6be5005d61d5cbd2cb4ebefd3e20fdd7d5b3dd0e5a1483a2bec0bcc0f0ba58af57ce12eb8962f093d1316d645e8a37b9963cf1c46331f2a3f9a91e1a3dfbb4d496628e405a767b1e5c1e530eb7eb3fae099b5f375860fcabd00ce4c0cefa36484299a64579b1aec880d89496d0dc5bed8b00352c982a9c75f13f909df2300c9e6c79305ad19a32637d19207fe58530969433948307dbf812a82201112564fd52dffd8ea200d0a6820423ed19773461c4afead5daccb42a2e266538660d147e77f3450d8237eaa708fe49b6d9481ec5dc7121da411f11f4a0685812e84d6a9d7b5b740abcac0bd7953d0789bc2fc21354c369f7f9323882b5688368829894010230644e816e3dc41e98c341da3c2c1cc719b42d4b3f3e9ba8fe16dbf26f6bed22a3ca0aef9d07d93d92067719ad7a58fd63489a1637b5752011f579aaeb74e58dc5f08270e553793d26914f9d96180872677c1e3027a59d60d0a692049aee780f7781691ca0c0751d677f481addb0ab637864b92f9fdb962e7f4f45b6bb0488e8e0a2729d93a40323b8a11d5a58e33a57ea02c69a271d5e4922e000d0a73209ec862189cba31549faf7f8a92c1ce32773aae6cb940f6f7c67c961573a9cd4ff965a2d87f2fb0f4ef8e03c50ab1ebac0ec0cf6d09f57654cc795dfda8afe912bc4b011a4c47598fb7963df1302e75bcad5a4a41e50e6dd0191978af5cd60f1325bc1d4e7a8e6d8416cb0585194509eadfec9096d989ad676157d7d0913d51a063b1b479935ef888fb22036fc3fc7293b3b4bc3320f4a15e8ffc1af9f693d40d0a2e20c549c228021255f3ffa568da1de61d9e9918dd9ffd678de224671ce11ee7f0ccc1edff459ba94e4e32586355fa674fff47d484d8c7e4cec9a197266ececb882272047f38886716abbd413b176d760d0a2020b58940833421df4bbf670f91236063f2580937a825b43c386b50df0fb6a2d2195ba8e2c6c51563303d3c35bf3d687bff1fd6b6ffb9dddf72286ae8a015a434cfc02c1f8686ba53d56fbecf1132923ace050d0a3a29bd6b6e4ef6b489fee76441feb12d389e7cb40c0d257b13f194f7e4fc384351174c378b85a5252147e951ae8411bea60899bab63314777932c83e1270437a0b67373fceecd96a280d1045856715eaadcee254110b3b7aca46c41914f2d21654272d124de275b59729024d47ff8ab89b22fe7852477c2cbe8bac525ad9518eaa0d0a20208dd25ae30a86b787a86dfdcb430078d74ec3267a243791881ecc0b5bead8cae9b4178322240882f56dabebf7c661515dc38229a1381ecf2194884f9127a12d96c29af1f3f94962748b42be9896a62ee3e5ef808a5b66a3fa1f33f2e5b338c2cb8f60184394f6f2efe9ae1f48a639b15cf5034df7b7687f0d0a5420ed5c6e5dded93b7310a645ecf311ab939c3a486d511ece8bfb2be92fab60403d249e62f06fddf17753c454ab14b80ac4761de0bb9cef9f5c3f0d0a68204b53388a72e04c61be8f19db704a23e64df9bdabe4d704cf081c16a9c577675462b736eecb27ad8575a861f64c0d0a6520444386efd170fad91d8d9d8936ed576c7554d5cebbf18191d858e0417a874a99ef45613b1f80326b40b4a6be0d0a2020644d21522c5ad49c6f06d75270f0c599066b4708e324ff499e5ab5d321742aaf33b36685e7dd9735ed1815c54c159db55f34eeed1bab87d4bef941677f439b048f559a997f8941b76d52bc3b2b63d5f1b21f227ac9c264314bd327037d00b8c7338b472b59ffaaa242d8c2d80d0a6d20d531096696d128efc37f518d9e9e6aa4699686751bd26fb3beecd352f49664e77d84cb2b362eccd159bf981b4a8114494f33164c90e94aa50dc7540fdc0a8cbd372be4bcc8054b6568c971bf920acf39dc73e64200365382698454d18ae894c75544855d658779e10d0a6120c86cfaebccd9cc3838d447652063382df27807a6f805a3725a60b84aa121ec23a8d2cf2d8da27975c9a60afbda150864bba9d37804ac8f4338b801ef6c5bac3852f4e84048c6f72564345668501dce6b7dd6ef76f11471e7456b501e8b258b4f72e649b45dd8c2bacd04b1c299c422ccafa0f3c00e470a70c56a978297e49a072ce4b235a9a7d41a64c760c1163af16bfdb2712dffcc255bb9df4123f57ea45f944ca20d0a6920c322cefe8772fefe54881cbf0041b7851c6b93d678c4575e18243381eb714e242e2d272ac7d101a0d53f1ad82d6c00bb8d99d9065c58cc1078a969a50d0a6e20a12d37ce4348fcfd601188d842da25855b2188fe46c86dd4ad962abe6327f3423f2d51febdf7aeb0323df97f42682c0693186aa043ecd18dc1496cc1f0b78bad4a22beead3db4659b34abd7fec095eebb6c96a8e766482a887d7ceca3f67d1f938eb2d8eccbf5dfc5774f792d4d4f8179ce17991303dc511782861056675386e2e948149e98042560120b7eea7185296ccff114364269114430e1548fb97ab5f05c0b903a32bdadf4d9a9a5bd2fbf54df5707d58ee14b7390d0a2020a2b082febb143fc54d0fb300401517b70a81a3c523b20e552b076edccf4d50eb41abd68df4e5d973dec9e5bad5338640e93c73ce0896b72028dc7ff4a0e4bc1f198ffb19d10b3dfe847cdec453bd02882d115a29e657c7b5e0564e0f377f2fb20a8dddc18d360299e440efa4b60145219d2ae07fb8b150be6cd68b00f2f624d69a5be89b9aba6c3b0a3f10080c0d0a6120cb8fbc85c160203f39649d36eb817bd7d53081f3a838e4761bfa94f04f58d1e431f2276e411608db6b59f31d96ecde3e818b489ee1489ff9fd558e124856857a7bc5270b26896b1721749ce1b5a0c922b7ce4413603d1b749173bbdc191411fa4ab542def6644c499bc60d0a64209a301e1b9cdecf4ec29afc1a407d688236ce6b6ecdc311f88e3da601d720174700f66d28646480a6db83d7a9eed22e0dde0e4458a7db1b8467ee46285a4a93cfdc10f21d4dd64afef123e87a11113786de50668bfd979f93b7aae014e3f309eb6489aa0b58d9c291e17af7d6ad72b65b69b6d4bee849fa358fba208407e051f80f24d07d45b7fd41a0b9771da1caa7cc77bffe995a2e2c0dbc1b9e0e0b73a514a84ddb2f6194b77a0e400d0a7620c3ee56f272667f9d49dfa1bdd9020b738f4cb57995b999eef66c5104432a00616d23249bfafa4001e1669fcc25dbf997508a4a701c8c631fb74b20c58e2e91532c628726aa2973f73c8ddf31f01082584f85692ea5212451ab1de77232ee85d2e6d487b2585fa635cd911ae389ea51930aea15e32a54feab22c7e1462dc58f38705ed4a922dc969f463cff60bca6e5139ce54d544e0d0a6120acc62baf053e52ec5df71ea2f3f7dbc443b8e9529243880b4376f51160baaffdcfb33e1e9658a20ad2c5adc447793439020db0ac7f001459c7f65c382191bc16b54d4b3f7a38445e57337111d9fbdd1c9383ac280451b03d52e416b39a5ff91bb66bb4925f7c5bdb7bfa62def65b5f21a3bc34b8ba335e88c50fb6a4afd8bbccd874b961a6d4aec278b3ca7fd4fdfede0f69e4a410f1279ce11c8b6a20247b0d0a6e207eb70bb633a6f1d6d8efb853b7a02b729a9a2e2f5520e953dfb10928614a53063aeba01674d82bda97e8d12e41ec15c4ed2b8ea6892f696e8b9e2d0becc6c9b18d87be6f9134d3ce964b928af7ba8606b83ae3d314ff1d61048dbfeaa3893f86279f272b1c247df2fefaaf286154af8aa1458cb2f2a2456a870d0a74209763b352d43543781c8abc626a642a923e41dca0a3099c7a6bad5042a4f472f28ff1c56e8dcfa149257be840573d62e17b9355785d52d57ed42c92743ebdab64fd37e42b64f10d0a61203b634d9c6bd4ad654dd9a46d90478c1c378eb877c66e82d4751a1d53284a867b7b1f5441f160fdcff3f6735979f26d8529a0fb9ecd6368e4956c082bbd623ece0645dabb6f49fde66dcc9f1432e3c18d569baacc2a429d5109fd77d135de797ca7c805760af594938293ddaf711b991ada1a39adc06c4c62e4b6be39da7c4b1dde1120898af64d7fe2f43f4d42541c76b9b0de9365d0aeb4a2f4d20d0fc41630ec032334e07c0cb51fcb67daadc920bde27f5189b289c730196bdf99c59c9ed4a2d9131bee88e98c0d0a6720362ce1ea9c95ae5ed7b7ee5e9366355aefbf1c9d2d590adf113ed2ade0ac99739da03a21579e4151c55f972e510ca6a283456e8d779b18ae427554aea9f4083aa39bf85d1a356bc5a8a830c4c3ecc7c233f99815d552c3ed6a0d0a652009faec42d61bcc1089187b4f311111cefef0daca7131395e9d79012f3d1dd3cd848e80c81e5c36a4cef5019d9fd6b32a75dda4988fd2e3ff9cefa66a17382f800158472e0c2e182852d0a2fe5869361a574c70f397b10201908090f69581789418a2fe58f9bd3bd82217dfd34f5392b2bb182106efc458c19f878a76c08dd8c5238ba325744e5b40dd1ced6548e4ea36e896bf4c84ff3d9fe6b2e33eed1be4755ef99c02490c76708ce9694a939c5266a0773d6d39c33c8500a1745325299ad27ed8e995dd4a1878398b928c7842e05debf3823906b5c45550f22046bbb5c72181c0a19e82adf12f40326fa60ff9418332f2350d0a73204ad1d75dccca2b189073b340e724a7400431ebfa565493bfa299abd71e1906dff641fc45552f41b89695bdfb2cb8edcffab810c4a065f1d9afd2e13197a959501a9a4be65e0de7d00e300a3b848d359464b852897508beb6c84272b56ba994c4b5fba0eaee1a740316c1cae1b2c7cbc9a1551fbf51a2806789cef7602dc0bd09a03b3cc5c88f019e70e06c677fc1695165737bccf8cb150cd52438b39c21ef790b40aa376c080e0d0a20201f89710ac2330a7155bd332883260401ec8b82679b862c5caf37bf3e7f643c93e3dc7638019d6d712f3dfb4e1a33ab846120a29401ed9cce2f04c7e6b632727b1ff5a63e64a41dc043b8c22c4898f79b10a87a1eff12463ed7ab279374d454a61ef18d2eede31bbf9a6bda0d0a6f20952e6bff47e012a5b57039af3aedbb3423302c1ef445652d6728212138e46338abccd0103fb6f8039609f68e432723fa57c0bd0d0a66207e8cee6b0d534c26329f93b6148eb4ccfef411547ba1f743285c007c998cc7814d7ffbe36cdc59b60d026139c1fb4e28e32fb30d0a20209c8c71041ac5e70c9d376442ca65745dc5dd9b02203db168a3ca53d31b9649104976be6e1e2d8d6a703306413035e857029f9486fc970016f2e1f89de52b737402e354e258cbb6d45c0c6c1952d6b92aedd025e0e4c52fa5f88527bfea82970bb659a03a2d5b0c81d5123d1867a69d77bdbb1fca950676d82ce3755300a10df309407305829ef2d80d9cf602ee7d6f41fdb541b99d42e98489b24d614162bbbd8fffd08b2d18a220fc3d113b9f1f50e25ab782f53c40e58cfc5e59e6bdd66a21e3986e5e5c4f31e43d90c809c8abf8c6b4754bce3d5b1a663f200e328e8c710a599d636599847188b4e47f190ed198b7d00d0a612091e5f33a11a04e689f9d649caa1b9a90da7f557de136a8e61653a0aa104eaf330ac6367a87f99d48d8db517431690d0a202084ffd16c7c24c0fbdda88692a46f93a66e9b9cbab4aeae5c090dd61be08e7b3ba38727e94eae2bd889e2e5c6a8c3b0ed9fcdea8aba91736a452010d5096f30ac4cb9a2998ca85bbbc2bc132f76cafa531429fc8eb7561e63d8380d0a6420c3659b0977fe471d026d28bb331d1bf2247a1e99d9f9d48b00f61e0473c06290d0cc1adfa569ab7dad0730395d07f3a849e185e4fc8b2de97df2ed374b133c947ed6e5bddcb0689f7d17580adec68bc21d57d77d0a449426cdea7e7ac8e90d0a692066e62a5566731d67d8d6bcc43bf81905c7d7e8c97f1b5a196b3e98c712f4b651fa85136f9c1f7a2529806235b89346b00207af3877db29208ddaafd17e9243eed830fa80d45fd8f99063a3799adeeb06001fb6b88e9bac523dcaa8a5d9a26f7aacd46df7130d0a6720a6a45d20e2b21a34b22c17759fe3a1ff1d5928b87333a201fd005e3e43657247064b37a360b2a3a2628bc376e5778b0697f321cd15ad2a85c6a5ef9ea33219e784a64e917b6ec63e1c3a29f4b50ec40e91d5cc3157dbaee9a9309e0526617264f46a911b8eb5c193b44f1ff7d8acbb5a51e86738dbb1f42fde8f2714dbb7ab65d6f1417ebd0d0a6920848ca071dcd66a149fc305f9f1f0c3634a3f3b9b24bb980e85e60683561c5db783c76eea3bf704c4ae71598d76f4b9e40d0a7420413b2daa0a25d83a46bf55e20f64c7157887f02705e1c551f53a3197290fad606b5b0214c3cca613b3df3043f7da2b8abbd5996a6e847c701b86bb1f4a7633f2b958260da722c76425e77b962567cea6bc2c94450fc6a09b1170e4b53cc0249f67431290586ad7e07bb8528c70e25f3134b929016886c9a468ce271be5fb2c6b47070d0a6120af85faef8e71447b6b90a10ccc17cd8962b33c093b0928508c6e6186fea923e78c430d5e00e7d4d7217d01d1fdb651415f573e7bf472249055ac017c4afd86718cece36859f316981dc0222562650a681a8f503bfebe8a162c7fa80d0a6c203a3587ef3312427a1f33244412c74368acb4f00b26ff8e9cdaa0f89658fda195f31f37e3b16a292ff33a46cff8ce9fab623a0932a70c3b94700d0a2020983efc342f3e9ddb7b84c902b62dc3a71d3f0388f4859a03b1537881f36fd02ecc0bdda9f7009c0dd8e7877448c2c23cc07766e57cc0e84786780ac62187088e6185fd938f667d37c067fab76495f85c80aa5ff08e26ddcbc72cdcfd87c163765f589b4bee1a0d0a6420b01f522bbd57144fa04f6bc2b8b6c6a07a3822429525bfa14be94c442f7e6d9c945807a09708e84170b36d8dce7f4652a6cc4e84f452f5610d0a6120c0bd8ea00e1a2cbecf3466d9f5826a35bf0e8d77471bfa7d348e87613e4279e848646dc7593d8b761dc27f854a5244e7ece059f6dec39632dff07aa7df53dc39f0ad61ac31c12d806f9c1a7a5e786909e47b702b89f640cb8447a9139185367fc947743fdd0d0a74209df964bde9e9d401dc6c4b3ea5dee2b99433cfbf55db5c72c4bd30ccb19714dfd27898609c05cfc913c8531a4645b36d470a97e78a7edb17e80e69814db4815d5b8abac67485cd578a1c14c9e21fba771471ec828d16078fc810caa791e82e606f24eb3cebdf2279dfb15b310d0a61200999c496ae6b2beea515a9c27070a80c88c4cb94372225ef73bd969a6b864db7344a4710b8a0a4fce1e7a6f6b942b8298748407507db695e05c7c36673794ce9e8ff89c9d5b16b3930ae3989bc29d597b79eaecfb3f05e883fd00ed3f3ff41006421023d16a263d55a6e4e163b062232ac2b4aee521e96d90f46a5d5f4287775259c6e7484630d0a2020ee75b750481297393144bf444adac55b3513fbc15cb463365774e511d150ae908aeb505e65df7b6c71fff120512e61c15c526ce50a08d63387bd02a794d8b08edf2eda3a30869a2a74e6491b740c44f2df51d8757bdf91e12616b9e2b3e5d40df4d4337c2fa5f92d2f107f36163b52bf3cbca4b5284af1cfb3b1f5d21936c92b7260625c08d631cd8b659a678d327c38b1a1ab2accaa630d0a73204e34c9aed34ee564ebc974430327796ace0632eb4c861815cfeecc69946ffca904af8b761d7da78bdd0653bc3aef44f996518c5838851249d6abfe2a5a946f05a7733f906624be72df50a23da61f13b539d87baf6f9bdfd672c45be6c585d7e5f9c082c7b877ef1abb2be00b55b8c03cb265503d201126f7088b6117da28a301418fbf42fe0a7c8dfe8f7a629382c526c6899e0d3d45e947dc4aaf961539b1be3ce59a6793d3bda358725d527964a1a9a50313a590328ff78ccbc15e1abd63bf1dae75d3892a9bc5072f0bbbffac8621e7ab661e33e8f868e91a782f0cbd350d0a7420f6555fe503464d09267f2db9328d7521e0fca7eb1d32d5cd459c3b609d1aff4574d72a247b2463fc0ecdae1928a0e6bc0c8dffb5e290285942224ed6e348aea98c3d35a15a18310602365ac81315824cafb3c351ae3f0b7030759ff36abd135d3958b1e83928b2176bae93ac396888bd6eb64fb418ca037efc0975f095251aa5aa3ce767495400e5801adea52e0d0a72207a4ea0f8256dd47d3d40ccf6fe1cad20df157ad3f15b15fbc076f3144631cee25c5c1a98f168555bab6a55bab90d8cdeacb9afe724f9bb16c6cd771ffe9893f0ff0324892c45f6360e25cf169523bd393fc9e829eb872d70595619a5cc8cfaa4aacf13bbdd7e086aae2886b8cec116a13e707e0d0a65207b97550659ff4decc16d143a53afbae032c4375d62437045ceaf14ec6f1d0c6dcc7b666e9db69c528a7afa15da8ed657c050ae662c16a09eb9c1845f27f238f79960faaae677b6f9f3e23d20250be482291b9873d49c3cf50aa279ca952fc96882177eb3e5d9f1a994545f90592cca1f589b4080a377db2d0d0a61203a568dc3c64de5d828033e1d39a1cc97b6a07476273afe70e855599115af6ff242f712f9f14256a59d934bf17fbc84b17f0015694e6f5eb9fcf727349a0eaa0a15b94499206e3f2f8fb40f3db3230d6ad1aebd7865671d8ec3a1f0bc1b2f9afea019560b8d03b46d46be344ae52a610d6421edfc0cecfcab9a0d0a6d208978679f49857f4700fb49fbf3b5cc679a54887e5b47a4be889a85e2f367dc8a6ca9ba3f32ac1a9f23ea95799ed3654b978bdbef4660fad214a2d72d7404943ee24f795d6290673aea995ce0e65a9effbacc5b6aa31f3b3bbaadbf3830426f44cd814346e9e24e0fccf47fb506000a919f51a9b0abef9d617a2ef11736b102ee53b2b4d384b74f53d64adb5afbabf8a2ee8993fa4c10e0fa73263c6f31f1f909f6e4e245cfed6a289c010d0a202006a7bd4e663e2245d613628077aa10cec85eb8c16f1b18e6419734f84b3af451b166ad2c254642823b544a6edc144e6c26482b9b7518a8dc0783cc35d2b649fce24254d0a31951f11a0ba5ae310b67265b7468ef163d65ee44b15a4b1e2311a385289401ba4360576109c8bd9e5d63aee055017b9029618efd5b5775c8e4b0de809ac5266fc57dc2decb2d19e936178239f5665a9e0d0a6120077510931dcd7d855bb461c608ddb07fb111abb97496e47b192fa02cc24d679f9896222d96d188ad204afc5a2e701cdf6fdd59e38a6d0921d09c7cffd210464603bcf025a918b1e75998211aff991e0faa3b1d0209de83e505a5f18fd27838fca08eaa57451d4d66edb2d140b568bcf7965cea8e762d759f4c95db1a6be6dccab9bb3cb67387a49adeb719d52c334690315848f1a808f1dd0d0a7220567d92751dd5a270f46d92be6616d649a1ce1fdd36226c5f810d4dc72f6ee0c5ad1e8b2230173ff8a534ab87303e36db11ad54b90ae9036e85888567aead28f17aca48ff09bb4327c596f9ce8b0027184aae005d8b847494c883905600054573e31e1d09348fe37a5482617dc252bb0a936a7d7785ac76bca94294948ef30b0d5ef70d0a6520ce7a6132c19e77238d007bcc30737306f57f58a5542f8554c82dba91d8f1622cabb50bd9e6fd9722e7cd4cd690ccc343ea8eb6fb4d05246f87e457f8f635220acdf8bd373fbc4fd72bf9bc607557ac0a0a4f5858b6f36990bd113d66178af836aca98c4b48f83d89b124cf7602a7c795f43b162ebf9908e4d708505a26cb177e204a07ff940fc8a0c850d27692708145295983a7c931d07383cd079132755019d735890e6b4bc7493b847df2615f4076b53cbc82db00febb0d0a2020c4118525613e87b5bf89fdf7b89aa3c6c57db937cbc65528afa1d0fe0e7b39f9b0dbf8243dfcc8df6c76ea192d5e4f74df147f9796724f13a5fba24641877d3848f4864eaa04689b230639aecc7f667b801514a0e1d28cca2481a64df89c584c9225e52e971f6a0d0a63203f8ae53b47209a24359517bfb2dd4034e86ad73dacd1e0806a252169a62fb9914345a38cdf6e5227f755fa2e415df05e62ecd76a17f7666645019a36011498f3a479bdbd1104e7264d7ed1d83007a6c34621dc853c48491c1fa25c63b9279c401a67a51878ffbb7a232ea5940d0a6c20c0054b7a036bd92aea66c07fdd1e18d6a7c4895522d179ec444ea2cfb647f019963e2904d243c72a159bd6800b81a1f79a984d30ae4066a8ad9df1acecad0240e57e3c9ae04254e86e41f28687c62668cac4d27f98e120ddabed76502f0ba22b2ab9f9e721eb1f6b420c7856d5400d0a6120e4832be3558b5ec9a426eb798e50b50cf3c905c5c3461584796b17bf69087f09f85f77f354ad25e5424673f2662f117061f179259eabd1f6c4678cf42e22adb31e17e65009b9cc5e159b1aa9ca8fe16fc2c52b57a2d170bd2ee91ccb99dda9d78b48b623b611a7c70f7eb9f83c28ca8d3a39cd78699bc65cf9518f6959d522d2c5e46efc479350b20d0a7220ba97ccd6b5c159b8a44635855c860c0c4a718584fc60a1a50391862d9be3645dfee5fa9d71c6cf6646299d3888b88bf4723c5d98a1a3adbae1ea8b675e73b48540bc72762a7511393eb8e3231dd1e10d0a692062fa25468d4c7d0296517b9cdb5691e31857af79fac43522101e210915e1b84f09a9ecc05e355c6c2da603e4d172a7512fa5c6d438987185300cc349c6819f69fa2976352dfe7b431867807d63873189ad0d0a742029a137ea0756b4d411c2e7b048cc0465a185915e735592075697bdb048fc9f97a33a17d824b8b7521effcb86504237363429682305058be85166b8a3cc6e6a7d34b534da92ddc5df4a76cb5f799ce418d7920dabd20d0a79208510cdf6fc33c67d4114dd161e64b5f1c85f02b55e1a5cc8bef6d0bf705f98fec4be34ce38f25c27d61e1403eb59acf65e6e3b9ac0d508c4fc7dc9c2bc3a192c12c9b967b888722c2bbfc621ec88aedf0e4151f6ea6700974031e3d0475035b442ecba202c498434b9977f8fffa80d0a2c200ce15b24ba56eea5884e1ded5d64b9dafe0f978e93ed8c37901c21af4f63697f19493dae37a4289b08f9beaf56d45fbc40559c9de7b02828c7456ff219e9a0b90822e32004447f90819ee810dfa999d08c1f0ee395a3de3b5a7341ec577f18f7e3263a51b774d4c10677e964951195d152aa0330d50e2eaeb4dbd48e6244640ff057ca19235d46495d182e0c12e8430d0a202005f4c66bc6c871a67ca42a5682a793077d67676319d3941e4495fe5c5553f78f285fe0e1384ac9220f77b772adade6a618d095e86fc1e2f7511ccfe51acc4c8f6fed2703c2827122b412e435a3eba575db63190f4a015677e33bd815f102712ccdc9ef199496187b6198032be829ebd52d6c48163b87bbe7247251138e77ace60c1f9668ba39116b24d1c2eb2e18b82528ff712b6f76b59de1a90d0a722060fbd6549fba215c5519cc58a494f0b51c1ce1e5ca2474eab509365e490c03794103c496446f524fa7ff55b89a0113de0d673ce2f73846e606713819ac52aec59bc7910f88eb7e4a5a51de35187176f64a1d266de5f336c2694c3d975bd4bebda548fb3460ffadd3aa4c2e8df6bf440731e6bafac8dc5c76bf64d9e91e69e1efd57e0712a4d5246b28a09d9175f7268bcb751835e7ac76351d3bd5de472490620d0a6520d368bf687d6942fe025ab4258b403dee8b4f458056a6650d93c508383629d65b5103675130b50c6da685088990a8ba89b877808aac4a78225cd9300b4f56813925a7fd3454c40b1e69f7233e9ff00ca3ab2a9a5dfcc78d191cbc534f8442974a22be04d00a43eb6749edcb342ffd24a1dc9dc2f770f066c73e2b3a5d233969f2928e401064f1c9e8a420efd1a628d4a56008b29b53987e2bccfd7253b5d4ac4ebe46ba45090d0a6120f5c3068758c2f30599e9947c5ebbf02e8f7f5321d8acfeb2ba0f6e7644466ce85a624e17edabda187022ae3dcee937b95a19869d0f575735fc982a445da0cb18eb63965bb15e9bc00df46d927d70ce1fbe26e2fbfed19cb352a35d480ec73a87f6dc05c33f5c5c75d07d27227cd5c32ca267de3951a318e8fd4e40d1fd35c27d272403d96445b0dcc4f8bb057286467ebcbab76ad52ce372cac94bc1e2484ec0ee5aac00aa0c0d0a64207ab408a47ac6a643c2153baa19af7a166c4174d24cbfa4d572cd7d086828de49b655d00710595bf06d0ce848ef4c1ed7b9603245e0e21210bc43870ce792842b5b97ae0f426df9e57221ce68f174b2c9d857fb119288a51a4328fb9a8e0d92bb862e42348db78a02d5c49ce65bed181ac578551e67eca5ba3f2d94858378a53a31375fdbbfad5d4a4bda0f08a398b779ca4449cc7d47c892621035307705ae13ed326a83102958fae85af00d83d6fa4040ed7d10017bd88705e11434318b31b7c379615acb0c6423a206f5d1851528057eb91a52fc3ff10d0a61203ab9bde3659650bb7d4f2392c8a9b8be1bee7543f9d176b9082c3311e0a1d9845b7a0b3ebb40928f83a916fff58ae81fdd4dc27afc9960251ab8485ed97937f214a4e60caaf2639fa71139b1d7558a1411903ffca31ef1df61d8d81e18d2b720d200db314e9d74ed79044ac463ff4eeb27daa31bb0b7e22a0ec0e9225d8f0980009df47627105d51208c6edfa718c894d7ea92ef6e06fbad37985952038e240f3943f09e9eacab84797f0468215640f5a9f3f4b0092b374f2cdc60200fff98c513c9f61c0d0a62203e2292df4d03f1b4b7c7dc7da08cc4f73ddf99002cfc72b9ddf545b2e256dbda08167290732305d4bd42eba3d366c182e4b1714bc6ef1b9b687c5bf36090cbde3e1867d901e4e483e34005732410bc882aa45d55c87c85d243b72b0d0a69204f7a0facb3c7fd8667203faba600a0754aa13f01c2fdef444ca7d6eb456b62ea36dd8fdf9eb85cd0fea7f92931f901245b2256b71f06403b231f3a3693a6acf8d5b9bf3e1151326337aae294a0b823910aa2935cf75954eac6c67b8a1be39845d753ba61fcaba66b2cbc6155c85d867e353c62653995fe4faae5a8559b783199b7805287fc9ae1e12d0fa61a3e3bdf19e9eb6767f3324f922c6e62c0d3ca99f2867331b1fffa4aa383da4510eb78fa82213b70b07a0d0a6c20c22d550dddb53a9de08f3a4c8c5caa7e85c00dac045715c80f5331125ffc4ea6582bc008cd5a7d94efa94d0cf158d059b2109f7cb21e2df6ff42c03af7b47113017965423983a5c532637f124ae9cc4001d357a62991de2876567569aa7e058696725ce1cf977579f10c7ce3561bb34f9c93780d0a69204984c3fc7922aaa9b443000c5c898f08bd2ca34a8ac5a78a1ca9de20396ba00ae6e3161739c32cef663d9d55edb0fa82e8cf06c2c6dd7ad981e2cdbb0bb2759511a9e465fee4b0c9c6a6e39d30ec0d373f67476dea79a41a3ed7b658a98588adf06c0ff6729a0cd3d06e07e1baa5fc1a26b424ff722bb5ce303b2d41288a37a1bb1390bbc0b70d0a7420633b1a45cf71df1da79d2b7347a6d74f2203f688a9769bcb6debee88a4dd333b51550ea57afd98ea3b2ccd117d86b41b53a45574d0e98588b1a3b2d3dd570259851896eeede3e61eb4527577d36d37eea91ffdfe9513c2cea1594c3cc16e33df8dcc3e6d91ed7eff4ecc14cd41919926bff2b90d0a79208f71dfb91623d5eaa9a453a05e7f48bee3dd09267b37358b6cf1df16c9be20bcb38954b541fc9f6488d3049046027013fc11c129c8fa1fc6c942bb1568113f5285ac0c00c4ee9ec95e41e5e3e55a23c2e65abaaa0d71c71eef6e3fbf00299d86abd587d415ff2d8d66b96b99d68438fce8345a9bb792105fb5243ee10bb0900c95b352f028c4b6100b35e1b52b4dfd475a140d55d1860d0a2020d900cdd1b3a97e3b1d0f7b1f714e43649f5075c5634a8fcd54c0b846ee285a224cfac5e674a697be7c575c7c66fc611384d447f86813bd602c4abca2351e8f1413eb4f10273101c1f398eef224a9dd0dd5cf49273bb4811f17f1dc9381cce27012c6d4590d0a6120823b838f94a4b71bab513e9ae4b36f9724d0c9694db74ca546671c14deed786ff63c502aff3396b8ad576bcd76d84aeb26f68c72e8635b4ba6ea9ac6a8cdb8b4769beddeb10862b316359aa93c95a08dc7105eb74b7ef02c7bde86a1b8c8b3a41738676779978ee1f0abbcb9daf0f7022c0d0a6e2012c6853733da2cddb7c7a58f79c77a9bb2358fbb170ec124834f0c4bd55eaaf0cc1109bd0aae1bfd0d85524742a818d0b1baee8e49de15b26d0233ce050221f9e07e2f75b676a67ceca104429ddc76dbef9053e4c9f935fe865a49eb232c98568e74ab2eae757fd122ab58629289b9b2387bad7302c5b0604b27e5e4c411f0c884196d9f419998652259ea2f0bd6ef1f822efa660d0a64205e35abb814d0a87de631fcf0770dc873b1ac7533be34b4743e8b3f7e890299299c057ea5fa7bc38ff767fe9c46ebe5ab62bb29463208e239797e3353bf559b81b551d8890ba97eba5318321f288f4b3d047a49a391407929faf7e94d4d91239de55bbbdb00a140d01fc9e60f18a07b42331f759e1b10355bcfef57c9e83b397d5205a3e4b80860cc4ab712bff37a90c5234ecc941bc46c58f86c7694f1835daeee77b207b47d96b658c1d1801b3ab6fb1a9e1c54a10d0a2020894e5b722dc3d1f3a0bd306de6afd137dbb463990e773a6c9f6cc087af6845ca68e5e815006309c3f2360831c3175148b1ef65e4cec0354df0037146a8ca49201fdadbab4be559e3aa2e6ca07dc97ba73e31753f2b7325df8dff461a8350bc80f277d75f37c2c2eb80ed7f85c13e33f057200635c397668b579171415d1dd58b4561b2df2c61fab3172f61ef832ac2405f57517e1922dee8ba0f70f77450b6c1bb863f6a62ec05dc4e9aa0669e0b8d6c53a31fa2c55b223ca2d7ac0d0a65202d52efe9c927413205fe447b055d8d3f5ab36fe0bdfd85bd2a418f11ceb5b0f9180e08db00e4852ae063e5b37d30eb5ebd969709ef9d71f5f6878d56f38072e865310fbe7db01df412f700625da7fb7442055098252a2d2f8ff9d3fb984f4ebc1c1480de5a39b5a807c5392362537b724935ad92b77b841ee3cc6f102299ecdf32fde87651972444d908f8483ea071d99f865c1e47e5861e53577d32ace31ae093ea8360ce5debbe53df1ddabb460c08fbf36052523978c47bf80d0a612027c752b38854e93e460c3f8966ba3662ee1874338638f12dddae70ea9cc5be2f80c90ee4abc2286e64e1cc8789ed7ba29129b20fabbd3f6a3e1cdad4cabf09206605b3969ed8f574565e9557bdef47556cfc5d34e36e097268699d0fa5004ad84de530bd99b8acbf046de63636772944d285921aeb3d7c8b0bea2505981f453da101d2e6fdfe2a527e5fc28ab87fb52347982863086f4cf4a8b2262ff5b96ceab6fbcde257abd6c2e7eaf76b0f2b40cae11628ae72aff2ed172e727897bedf5c51fa8bc6219571fe01523e5ec882a62e1e6a15a7d0e87e2c1a02297ba1a06356e8476d1af04eea0d884877d00d0a732011d45f56e22fbe0795930925c5e643a72cf701d4b348779f3a7b03c5e6984631f7afc76bc11b599cb1f698e8abc69c8081c3fdb8c26827ab698b15ed4daace45b8930a83e86cafa4be2a974f92e5ffd684b38e11fca2d6ee43ec5d4204d1504b390c3be4f95e9f4edb754ae649ef7b06dc65f3210c8d621200498c905760a75c09445a6ee361cbed1d6d5e90a3fd497d4da9e024993e01f88cd9359488007779f8470ca381d6ce49128256ce88ad27ad949a7ff0e25b6839e09ee7e803dd2648912c002600a08af49aed472c5b31bac47a6f9f7bb80d0a65206af63cd5e96f774041e85a40d85f085ff647639ec907e6facc4998b3201591cbacc1c3527d05b8d0233f4b7dba2c542d66ad9c401f845f587a553938116165642c572b032a2111e809d9138816fed5eb722dcd02c730685516d8067b91403af5a776e0a056219595750e7b915f6f11c5d1eb1bb6a8f89726ae0efc82521736d53cf9c2587961844faa7a10acb00267ffe95845871c1e2130dbb64b74d0a2ef55b95b61f99137d4d2c1b78f18cccd8d5f490090749f780d672b9103acfc92188c06d79997fdd023924a0df69cbf5b647ee336461a3f0b28f471170d0a2020e722cffe1ea849b5aaa80ba7f1f26ad7bb0ded862ad99c4c15b1478c91f76f83f82154175acd033999e2b64ce5f805f301118abfb76f13ee2fdadf9becd2685da928732ffc094209c5e096504c5fcce0d8485735b47d548544178efae1aaf9a56e53003170c9eabc906a619c6467fda8c811b161aaecf2dc98f1255599c7104692e401b6eece678e552e228e781f9670e374a0de8fc8f15e354bc5bbcf9bfbdbcda316d1c84844a4b67a4424bd3d731938af334ea097c067106a9eb210008cb6afd258eee097084e4da11d4b57dc32854871210d0a6f20b16c8ee7abec8854d61cba7ee4bb60a69ba1e2a2c5adc3313c6e9fbbc9ba440ff315a4b9c07936790a975d57e90440374ddabfd14467395b8969dd68dd7eaf341c9510735b757ca7ffa5e3228ff0ac42a8a1af8fdd645efcd07a463c3eb681e7779e970b80092343d15aa93d5ac35d94bfbf597aeae2fe5da2f4517152fde8d4090baa3cfa6fd9f593ae112166f0dc384eb0fd13d0267750648799555f0804d555385f3de31e2edc39ff0d0a66206704b4ba924132a3e0c7ade69964c58d1b0e559767efc0e3ac73a47100095a11ee0091a0a88885293ea76be5b8427613205568f18c039e8be1d67b545c1ad31275ad780a52ee5be8afde7823e2636be5fb73098614716d98a8515dbe758cd1f67edd30d33264fb8c216957837b34f7fa818d603d5b4bc5f73076db3b1b1a48c6b37f9cce8953ae7f67f613380d0a2020f03904b8054c357ae60ec837e4eb1a9d152a0c7597e8bb99e3df4f59efa3c486b8e551e403fb267b967573a3377bcfe5c6005f6f865673889d8d8c7f6a0376f8afbcf39e78227261c116a832b5fe52d001612a36107162f81147b8a172ef2599a9376d475a98eeca6d48bc49a30d83ea935c7cae8b875186a3d12b8be6688090d061d4f6a1e5b14fe71891d973e898030d0a752099c07a05826c9eaa0f00e94268b8b4d76f2746725bb319c0041874a704dbd08cff37eced6f2d1a2c397ca36d49697b210b63a969405e88fef16c58fd6832a89255291de37aa4cc72c2a73d6157b86a5b779112ddc39382edd9333ba36d0ee96c7a859594c704ec5c290c6dd4fb86e6db7f4bff57660554e7138b7d6188bb4b77996f9e8225e02cb5fe6d109b6370fed27e3d0d0a6e20469c411026fe9816cf9ed22fb7b20b31ec11b964a508fbf099296771952baffdf597d90438e4e53714926d971aca68ca83a459eaabae572a5f7dcd37a452ef4c171ae492293454a97d21f5378a5903c086c4b692749214f25857d6849544ef12b10230b087b395348f615a044c165df80649f1ea46de553b82389ad307df29edc8d94a94a648964461edc693f86d47ffa9a81b3cbdf7e6e2e96136c1f6d5a231be03844d624d59e33b37fdf80d0a6420509801d74c88442dea5290ccaecfb341de0a0f33bedffabf2c91113cf8570db02720603423890f7b834e2dd0c8dc6f90da816eaceb1c7dd684214fe6a3bf3af22ae70539f4fb3b2f41911030371ffa0d0a652026fcc39b3a037ee05b72d5104e22081aa303754ef3afc157dd48dd9e18c1c889c3556033e3ea385b05fa28c49c3b0783b8af685b02063ce4b145d124659b8ec52f07159e302135e7f5cd237e5b19f525180d0a722057b98f5841dd11e9a7ee56cff9293bb382d082b78918c59a3934e78889d7ed3f8828930bf6e9deee084eba8caa9bf589a5acab305d9eb07cc8c3e765570ac78fa3a5098e484f9610083b1ce23ecbb01f629c29348a0d0a73201162c1601cde400947fd52913ea8401f06c03402593dd35b01652fafa547836dde6a94bff5166d07e06e4ebc760648660687a38118d540e7cc7464f221fa9f8000bf593a585c2dc3e07f084c4facca98d0701c227b67ee0ed302569c493b5660c421ae17062f81c38b50ddf90d0a7420c4d02934e558b3e19e1c7cd1ab61578e494e0f0bd3448a4a3c9de3465eb5b4ce71b9555443918320446263890d26b7c494b21447c013edaccf1d7ddbc1a25f38f21398bb36547c1c976a472c3b733014cff09b176fb8bbd1360f2f57b1da5509b09689b3b6845b65843516e418873c9fa1271a7c622d6f9d3b3d7b49f2ca3cb466fe76da3bed0b7597fdfebefc4b5c0cef015081a4d1ae3518348210060d0a6120fef0e6eaa94a61588e8403d09b4f233e1aa1e5ec82ab24c3594524e0ea21e473896a2414a8df276d712a45525f263aeff0c0a85dc01ad631dd00093151ea9f89be5045cd1b1a1b96ba2b38b1d7cc89972f9dcf570ca700d97e3828ba5f33c922f130b9382fedea2c54e0652c0a51da7e3dd6ed6e42a1150f86b18e62eff03d715b86e5052afcdf3d4dd294d99eee841b90a26d9268b73232fe8bf556071f2a0f7f88fe0a13d948adf1dbdb9d6910d43fa9739e751050953fac0d0a6e20318b7ed1cd842378e41e5ef5c0ac515c7366345e7c430458857eec676e55550cf4d7450a296928b98fa03fa75281e18f08c3b4c63620b64e431f53a5712f3c9cf7b864e2ce9aef1413b72f1f28391b90308a7e06503fea894763abf65ce0e36bdfd0a71b039684506f7c22c31f8f5b58f7e9e2bc6e9d1546480d0a6420e1f39b229f140387977acf2defad5d687e5199a25fc7e3e54dd2023036df7e68746bf1bf923d6e44d9bc581ae99bb28d0b3ad0fbdf0fd54914a6826fa12d07ff49fc539d11e90cab9fb2812b09ba3626a0a5a8d2cb02482a747e14587e6ec6f66a854ebcf754112d5d66772651786eec2fb87102fbdfe3dbc672263c4c2d0d0a69203376b674f634c799ec83ee3b1fd5a73284d66fec50447fba32c8b70ff2d136a3205c83dc2fda0e37a0e9f97713630d94d569e5400031629514cad66da8ad2cff1a07b0a7c73365a686e8771477275096707b3af22e614a4d7720237350e28d674410c753f211abad545e8a1a276b8ddd2966f46e5a0d01d80d267cbf2f6c660d0a6e2069effc528ae49e4112ce0881ae09339024667d4431ddfa0a968bef88505de574d01ebe2870e2bd68c368e29285f41a6834cff7a0b5d794f447d6ab005211a759bc98af052578cd944a3f10b62582d4a9c3a0820750eb4b9fb05562054a5cc23344dbbaf8bca6c7ec5f0962682e0873755b1962eeeed4b1204c64cfa755f7901042429e88c1c2b610f47090cf07bc86d55841c41544a1c8dda414f42db0736e9dbc019dd46e18126d0bb79a88c67e58ab0d0a6720a4a7b983c1d3fe4808911c0130c210a3ba0019c4ac9a0470afd48d688eebfab00647a1c865572e54ce89b2b9905456d4baa83eae45be83709d0473ea5b3e80f89f4d0ccf9d929c31b5ce3531d3bff2e540eb0967e974874c0f3dbd144fa55233337a7740b57f2044886c947bde4330c446a12f5a81a06c8fb26fd789f359b7ddc3716c2199e7d45e75332f1c89e518bf71e339219351ef2a4a0d0a2e20e4ef514ef69eb2cc196ebf8611334ec1aff587371a8e91e21d640cfec661c27ba31e0db979109ce958e9187bc31a9a3f51d176d56b6c5b10f1691f2bb6b4a8c41a55e1d9b3c1712c83131d3ef6cfb1cf5ee61eaefd203d0988d5d88fa410c61ce48f3d05a60065915f089f0db66e6cad0d0a20203e7cc17ff531668a03e8ba840e5440a992bce538f94ddbb81e8c4966383468329c0fc689e65e46d4b18488be8b00b7f14d29ef53761a516dd741157a80b9609dfd78c3f0b219d22bfe1cdc617e2dd194e5807eef68cd9caf6ac7c059bb6c5f26b7cd81614d5be7f82030c8450489ed9eef4ad5e335466e4e76315e40a6cbafaa7e9dfcd7e0b87394a3817ba3fca9fc4a09f2b84b280bc184fb96e78357027a24d36ba2e11f0d0a4c20b93445f22110cda9200b54daaf1f0bfad67b3ec2470b8f205213fc864fa82e12b14992b64dd8232e9ea3953c410bbd9642162df9938d644b25111a8368e8cb757ce26b4ba700e51e3d1afae490a7f7e6e4d9af9b282a834455ca2cc87b6c577c0cf72846b222f561982919c0276a2066cf13184024e40cb5965b6678f2e1328f1e067ec47fb00d0a6920554ca17873089acb6d298dcc0a99504e527fa35710343ae378a332c28542f316b9076aaee0ff9f5b61683d31022740e4e47e5c200ac2d32376dd043d6f47d8e0b583e9947ae06da7e337a456273e0acdf59d23263d7974411008162e49aa62bc06abdbf848ea47b534715758c042c18709f49c701ce7c48b3a32361696fedc4749dc0d0a6b20f7916ea5374052277b8473d149459fd49b42ce04d0e3c84db44eb15db4ca420381279f3326db892f24608929619f8bc76007a77b1cf9b6567eee5f1d76d8abe84ea5de64654a5f409d36f4fc9f24fc9c846928250ec917b930e47aa073b717bba66521c58e75a8ffff43c31dcab3080d0a65207eede4f65df954a2d57ebb2ffe290ec1d32b9c7e71004349161cd7c2e227265597fdf6ca0eae35058cc2d8e964bb81a750339aa600574095b4dbf0091a6e57146069c76f2df30178fd81f54bef9b2a1b11d912f9dc1f0638e55f68388ebf29d4a017bfd265106eaea8b3e68fa023338604bd9d7b3a776981dbbc83d699c8c8bcad7dfc6df86a7ac247484d6288e9a8e376428063b3f51b92aa19e841fba12859863e9fe6b5410d0a2020257c4b62f1e51555ffb134087a11acd287a4b8d033590240faf1cf857a79d5da73115118621869bcaf30953e02044097344db0f749b7cd3df6a5f65f2db35ffffe198ced24412a5e61ec3b3b30bbcca94d45b371f1a8bf5961db810ced1a078e5c8ec90d0a74206903e7d157671c18a0aeded00e387b64e629856732d487903ea7e5ee8e15045d4201b2907efc298e952983e27ccda2824e6f74a6e84eeda9cd1aa39e39eb9b4470ee92e184b7d1d8330461e4af0f233c4dd5b20ffc3364464db8625fd5904211c4b677f79a5c29f6d785ef0ab3df70069a791a4e1c3902b71d2214a33eabb1e90ca9125a3b0d0a6820f88f524fd0323808d6855c4c2f71c5db2f2af7fb4c8d3d33c09d3fc734963051213604dfee03b313e5208fdb740d186c193c6967c8a88aecb8a2822dc60c1b008d87f1542f0854edc33c47861442d79f8d556b903a1e689e536fbf2142f24407ba4222d8d7a9868412a9a9aa74fa0aed6b1ac8167eb08347cdc00389ccb29c6debce71f80d0a69208c23c1f0b8d92eb72b7c25b7239f24e6d4d467b26758180d0a7320690c5772a50f6dca26bfab7d1c168953fa9d5dae1cdbf6c89cc93f45a2faf6078b5348ef8081943cf005b8f6a5f5860750baa81a45f2befdc40e8dd064b3b029c8cd823fb2e53a18c0251f65bc26b7064eaa0d0a2e20489119e7391040a09191d70ff16dd52961a73fbb74913b1fbf29fc344ed575ae8994f070f14485c1da28371a823050ada4cc03a318f28f1f9ca98d467840bf71dd9b1746489442aa05de87b1780971c74b0f35e7bfe6f1ccdf29c1378ee6b7462ddaf5e2610d0a202050a69b7d9ce2d67914c85e92ecc72c1e1097235cee395b02257f175259ac93730ea2becd4f1895282fc14aa0f98806c2155624633364dae4277305ce483104d0e76ed59f3e0d0a3a290e917bf68aade88056316e361684e59ad4925b7e3cd675aa61836027e1c056f555a117d2bd4fd45cf507760abd6363f94149c566eb86b180e3498ae8e4ed0d0a2020b74016ba601b19300f6f6dd300f0b4d7119db0fe263ad3ee9f7dc4175b36a843d6b983cbfb5c381d781ea61d27102576ed07330a1cc9923f93bebf0d0a54208ae7ab43255173c03ad0bbd41a8fa6348d1ddeb9114a8463871308448fd0384bbac154aec1e4a4efe433c4ee8a4a0d0a6820df01f7578cb080f588cf6b3141867094c9765f3b1245bbebfe185581c80dfb7ab002ca47cef7e9ea5c5a1b9a65db4defcce1c9a6bbb41ed1b78bc3c6cf84fb1b38aff6712201ee69b58280337da9d2ede8868bc371359ebe10aaa681d460f375d08295a3038a28b4e6846f5c9de34aaf9aa8e4a75cb78c19a7db607bd97b96c8a79cfe10ef942743e068118f330d0a65208c63706d10716f3a638556dca971e905fafe65fb046c8da4bd5ab88517da789501f4a9f23e655154a053df358068de90deb919c0a74a5cfc74f632e6ff1f0772ee570a76d2431b8c0735431462de5bedcaed963e97cb7cbad2324a52408d91cccf8a6730ad281b3d1940ff933d93efe37dcbe1cfa00218c86ec92fa90d0a2020e6b2d2c1e783954de27288e778e76b835ce72d922bb5143c860f7c964bdcc2ad1cce4c8d65d9a6c9815ee38c6058b03bef18b8b3dd88e268700d0a6d205c52a0dc69c8cb3b736f0ca20f3ae6b78049c47268d3a777266b2f0b21480f59fcb5d9870be4e7d2e07b4c0d60d9970f79d81b03444fbd2477e60d71e86ed656749e89239710c610d73673710d0a6120d2bdcad090f6f9a0b4e0b030d233e0287a1d8593d75dc9f0b986fbdead4568b524815cb03074f76b4881badcd4976f4e420ad93bd350589d6003aa02e9d6e54cfc73018df041280d0a6920f24b22af03b00b2a61d577e3b9688cdecea331fcb5409a8edda7952899692a88c88e15521ff4ef30c25363efd03618ed432c326477e81424db17ee63175b9d3fa2d3a7c70d0a6e20632fa8c0376c0e15e278e8ab2dfa992c6946826c534e7897175529d8e8677cf44d46cb9f725ad428f40f2842059310f155e5124e1ae7f1f803b04b01033b0cf8d3b071b616bda9fb3a3896d78d239361c8efc436173d5d0d0a202063a50c95d4f103448a782e167218c45a68ae44ab75c3c19367ab89df6c6159f20ab9562ef87fc35739bacd07b44d6edc951afd019f82d1bee874f4eef7f33eaf8055affa89948e74b514591ce348c0304f8738ec4a0538a65c2cc18bc6ec102e3ed360ff5857b625481947d4857060e12a97e214273df03f7de2d1e9b79231afbe1c5a8cc90934cadefe9b600fb36febd71f107b9275b22c130af4723a92a00c2a67b2583d1b4d5c03a6721bab338631cc34c7465015af934c57da63c10000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/share/examples/BSD_daemon/README b/share/examples/BSD_daemon/README new file mode 100644 index 000000000000..cbe8c96bf7fc --- /dev/null +++ b/share/examples/BSD_daemon/README @@ -0,0 +1,83 @@ +# ---------------------------------------------------------------------------- +# "THE BEER-WARE LICENSE" (Revision 42): +# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you +# can do whatever you want with this stuff. If we meet some day, and you think +# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +# ---------------------------------------------------------------------------- +# +# + +This directory contains various stuff relating to the FreeBSD daemon +logo "beastie" and graphic profile. + +Kirk Mckusick <mckusick@FreeBSD.org> holds the copyright to the +BSD Daemon and you may need to get his explicit permission before +you use it. Please see his web-page on the subject: + http://www.mckusick.com/beastie/mainpage/copyright.html + +beastie.fig + An Xfig(1) drawing of the 4.3 daemon. + + This rendering of "beastie" was produced by Poul-Henning + Kamp <phk@FreeBSD.org> and is released under the "beerware" + license. In addition to beer Poul-Henning collects FreeBSD + merchandise ("nudge nudge, wink wink, he said knowingly.") + + In difference from the rasterized renderings of beastie, + this vector-based beastie can be rendered in any size and + still look great. + +beastie.eps + Created from the beastie.fig with + fig2dev -L eps beastie.fig beastie.eps + patch < eps.patch + Before committing this, clean out the comment brought + over from the .fig file to avoid Dollar-FreeBSD-Dollar junk + +beastie.svg + Created from beastie.eps using an unholy mix of python code + and manual editing. + +beastie2.eps + Written by Rahul Siddharthan beaste2.eps is a + smaller, simpler version of the beastie eps graphic. + +eps.patch + Add some comments about tweakables in the .eps file and set + the linecaps to round to improve visual appearance. + +FreeBSD.pfa + This is the font used for the "FreeBSD" text on the CDrom + products from BSDi / (Walnut Creek). It was originally + found on the on the WC/BSDi CDROM "Font Garden" under the + name "NRBWelshGillianBold", but the designer of the font, + + Neil Beshoori + NRB Systems + + 44 1273 581366 + besh@cix.compulink.co.uk + + has donated a FreeBSD version of the font to us and allowed + us to include it in FreeBSD with no strings attached. + +poster.sh + An example of how to use the stuff above. Outputs a simple + FreeBSD poster suitable for A4 paper. + + If you want it in A3 format instead insert the line + 1.41 dup scale + above the "/mm" definition. You can scale it to any + other size in similar ways. + + +If you want a GIF with transparent background: + + fig2dev -L gif -g '#f0f0f0' -t '#f0f0f0' beastie.fig beastie.gif + +If you want a PNG file: + + fig2dev -L png beastie.fig beastie.png + +enjoy + +/Poul-Henning diff --git a/share/examples/BSD_daemon/beastie.eps b/share/examples/BSD_daemon/beastie.eps new file mode 100644 index 000000000000..587fe508c36b --- /dev/null +++ b/share/examples/BSD_daemon/beastie.eps @@ -0,0 +1,1507 @@ +%!PS-Adobe-2.0 EPSF-2.0 +%%Title: beastie.eps +%%Creator: fig2dev Version 3.2.3 Patchlevel +%%CreationDate: Sat Mar 3 15:57:53 2001 +%%For: $FreeBSD$ +%%BoundingBox: 0 0 384 417 +%%Magnification: 1.0000 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin + +% This controls the linethickness. I think large posters look better if +% you use a value of 2. Small daemons looks better with a value of 1. +/linethickness 1 def + +% If you want to fiddle the colors: +% col0 below is black (the lines) +% col3 below is cyan (the shoelaces) +% col7 below is white (eyes, shoes) +% col13 below is green (the shooes) +% col20 below is red (the daemon) +% col31 below is gold (the pitchfork) + +% This sets round ends on the lines, this looks better than sharp edges +% but I have not found a way to convince xfig to do this. +1 setlinecap + +$F2psDict /mtrx matrix put +/col-1 {0 setgray} bind def +/col0 {0.000 0.000 0.000 srgb} bind def +/col1 {0.000 0.000 1.000 srgb} bind def +/col2 {0.000 1.000 0.000 srgb} bind def +/col3 {0.000 1.000 1.000 srgb} bind def +/col4 {1.000 0.000 0.000 srgb} bind def +/col5 {1.000 0.000 1.000 srgb} bind def +/col6 {1.000 1.000 0.000 srgb} bind def +/col7 {1.000 1.000 1.000 srgb} bind def +/col8 {0.000 0.000 0.560 srgb} bind def +/col9 {0.000 0.000 0.690 srgb} bind def +/col10 {0.000 0.000 0.820 srgb} bind def +/col11 {0.530 0.810 1.000 srgb} bind def +/col12 {0.000 0.560 0.000 srgb} bind def +/col13 {0.000 0.690 0.000 srgb} bind def +/col14 {0.000 0.820 0.000 srgb} bind def +/col15 {0.000 0.560 0.560 srgb} bind def +/col16 {0.000 0.690 0.690 srgb} bind def +/col17 {0.000 0.820 0.820 srgb} bind def +/col18 {0.560 0.000 0.000 srgb} bind def +/col19 {0.690 0.000 0.000 srgb} bind def +/col20 {0.820 0.000 0.000 srgb} bind def +/col21 {0.560 0.000 0.560 srgb} bind def +/col22 {0.690 0.000 0.690 srgb} bind def +/col23 {0.820 0.000 0.820 srgb} bind def +/col24 {0.500 0.190 0.000 srgb} bind def +/col25 {0.630 0.250 0.000 srgb} bind def +/col26 {0.750 0.380 0.000 srgb} bind def +/col27 {1.000 0.500 0.500 srgb} bind def +/col28 {1.000 0.630 0.630 srgb} bind def +/col29 {1.000 0.750 0.750 srgb} bind def +/col30 {1.000 0.880 0.880 srgb} bind def +/col31 {1.000 0.840 0.000 srgb} bind def + +end +save +newpath 0 417 moveto 0 0 lineto 384 0 lineto 384 417 lineto closepath clip newpath +-51.0 455.0 translate +1 -1 scale + +/cp {closepath} bind def +/ef {eofill} bind def +/gr {grestore} bind def +/gs {gsave} bind def +/sa {save} bind def +/rs {restore} bind def +/l {lineto} bind def +/m {moveto} bind def +/rm {rmoveto} bind def +/n {newpath} bind def +/s {stroke} bind def +/sh {show} bind def +/slc {setlinecap} bind def +/slj {setlinejoin} bind def +/slw {linethickness mul setlinewidth} bind def +/srgb {setrgbcolor} bind def +/rot {rotate} bind def +/sc {scale} bind def +/sd {setdash} bind def +/ff {findfont} bind def +/sf {setfont} bind def +/scf {scalefont} bind def +/sw {stringwidth} bind def +/tr {translate} bind def +/tnt {dup dup currentrgbcolor + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add + 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} + bind def +/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul + 4 -2 roll mul srgb} bind def + /DrawEllipse { + /endangle exch def + /startangle exch def + /yrad exch def + /xrad exch def + /y exch def + /x exch def + /savematrix mtrx currentmatrix def + x y tr xrad yrad sc 0 0 1 startangle endangle arc + closepath + savematrix setmatrix + } def + +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def + +$F2psBegin +%%Page: 1 1 +10 setmiterlimit + 0.06000 0.06000 sc +% Polyline +30.000 slw +n 2174 2967 m 2179 2956 l 2183 2946 l 2189 2935 l 2195 2923 l 2202 2911 l + 2210 2898 l 2219 2886 l 2227 2873 l 2236 2861 l 2246 2848 l + 2254 2839 l 2262 2829 l 2270 2818 l 2280 2807 l 2289 2795 l + 2299 2783 l 2309 2770 l 2319 2756 l 2329 2743 l 2338 2730 l + 2347 2718 l 2355 2705 l 2362 2693 l 2369 2681 l 2374 2669 l + 2380 2657 l 2385 2644 l 2390 2631 l 2394 2617 l 2399 2603 l + 2403 2588 l 2406 2573 l 2410 2558 l 2414 2543 l 2417 2528 l + 2420 2513 l 2423 2498 l 2427 2484 l 2430 2469 l 2434 2453 l + 2439 2436 l 2443 2419 l 2448 2401 l 2452 2383 l 2457 2365 l + 2461 2347 l 2466 2329 l 2470 2313 l 2473 2297 l 2476 2282 l + 2479 2269 l 2481 2256 l 2483 2240 l 2485 2224 l 2485 2209 l + 2485 2194 l 2485 2180 l 2483 2167 l 2482 2155 l 2480 2143 l + 2478 2132 l 2476 2122 l 2474 2113 l 2472 2104 l 2470 2094 l + 2468 2083 l 2466 2071 l 2463 2059 l 2461 2046 l 2458 2032 l + 2456 2019 l 2453 2005 l 2450 1990 l 2448 1975 l 2445 1962 l + 2442 1947 l 2439 1932 l 2437 1916 l 2433 1898 l 2430 1880 l + 2427 1862 l 2424 1844 l 2421 1826 l 2419 1808 l 2416 1791 l + 2414 1775 l 2412 1760 l 2411 1746 l 2409 1730 l 2408 1715 l + 2407 1699 l 2406 1684 l 2406 1668 l 2407 1653 l 2408 1638 l + 2409 1624 l 2410 1610 l 2412 1597 l 2415 1584 l 2418 1571 l + 2421 1559 l 2424 1545 l 2428 1532 l 2432 1517 l 2437 1503 l + 2442 1489 l 2446 1475 l 2451 1462 l 2455 1450 l 2459 1439 l + 2463 1429 l 2466 1420 l 2469 1411 l 2472 1403 l 2475 1395 l + 2479 1386 l 2483 1378 l 2489 1369 l 2495 1359 l 2502 1349 l + 2511 1338 l 2521 1325 l 2529 1316 l 2537 1306 l 2546 1295 l + 2556 1283 l 2568 1270 l 2580 1255 l 2593 1241 l 2607 1225 l + 2621 1209 l 2636 1193 l 2651 1178 l 2665 1162 l 2680 1147 l + 2694 1132 l 2709 1117 l 2723 1103 l 2735 1091 l 2748 1078 l + 2762 1066 l 2775 1053 l 2789 1041 l 2804 1028 l 2819 1015 l + 2834 1002 l 2849 989 l 2864 976 l 2879 964 l 2894 951 l + 2909 940 l 2924 929 l 2938 918 l 2951 908 l 2964 898 l + 2978 889 l 2992 878 l 3008 868 l 3023 857 l 3039 847 l + 3055 836 l 3071 826 l 3088 815 l 3104 805 l 3121 795 l + 3136 786 l 3152 777 l 3167 768 l 3181 760 l 3194 753 l + 3207 746 l 3219 740 l 3234 731 l 3250 724 l 3265 716 l + 3281 709 l 3296 703 l 3311 697 l 3325 692 l 3339 688 l + 3351 685 l 3363 683 l 3374 682 l 3384 682 l 3393 683 l + 3402 684 l 3412 687 l 3420 690 l 3429 694 l 3436 698 l + 3443 703 l 3448 709 l 3453 715 l 3456 720 l 3457 726 l + 3458 732 l 3457 738 l 3455 745 l 3450 753 l 3444 761 l + 3437 770 l 3429 779 l 3419 788 l 3410 797 l 3400 805 l + 3391 815 l 3382 822 l 3374 831 l 3365 840 l 3355 850 l + 3345 860 l 3335 871 l 3325 882 l 3315 893 l 3305 904 l + 3296 915 l 3287 925 l 3278 936 l 3269 946 l 3260 957 l + 3251 969 l 3242 981 l 3232 993 l 3223 1005 l 3214 1017 l + 3205 1029 l 3197 1040 l 3189 1050 l 3182 1060 l 3176 1069 l + 3168 1080 l 3161 1090 l 3154 1100 l 3148 1110 l 3141 1120 l + 3136 1130 l 3131 1139 l 3126 1148 l 3123 1156 l 3120 1164 l + 3116 1174 l 3113 1185 l 3111 1196 l 3109 1209 l 3108 1221 l + 3107 1233 l 3106 1245 l 3106 1257 l 3106 1268 l 3107 1281 l + 3107 1294 l 3109 1308 l 3110 1321 l 3112 1334 l 3114 1345 l + 3117 1356 l 3120 1365 l 3124 1375 l 3128 1383 l 3133 1392 l + 3139 1399 l 3145 1405 l 3152 1410 l 3159 1414 l 3166 1416 l + 3175 1418 l 3185 1419 l 3196 1418 l 3208 1416 l 3221 1414 l + 3234 1410 l 3248 1405 l 3258 1401 l 3268 1397 l 3280 1392 l + 3292 1387 l 3305 1381 l 3319 1375 l 3334 1368 l 3348 1362 l + 3363 1356 l 3378 1350 l 3392 1344 l 3407 1339 l 3419 1334 l + 3432 1329 l 3446 1325 l 3461 1320 l 3476 1316 l 3492 1311 l + 3509 1307 l 3525 1303 l 3542 1299 l 3559 1296 l 3575 1292 l + 3591 1289 l 3607 1287 l 3622 1285 l 3638 1282 l 3654 1280 l + 3671 1279 l 3688 1277 l 3707 1275 l 3726 1274 l 3745 1273 l + 3764 1272 l 3784 1272 l 3803 1271 l 3822 1271 l 3840 1272 l + 3858 1272 l 3875 1273 l 3890 1273 l 3906 1274 l 3923 1275 l + 3940 1277 l 3958 1278 l 3976 1281 l 3996 1283 l 4016 1286 l + 4036 1289 l 4057 1293 l 4078 1297 l 4099 1301 l 4120 1306 l + 4141 1311 l 4162 1317 l 4183 1323 l 4201 1328 l 4219 1333 l + 4238 1339 l 4257 1345 l 4278 1352 l 4299 1359 l 4320 1366 l + 4342 1374 l 4364 1383 l 4386 1391 l 4408 1400 l 4430 1409 l + 4451 1417 l 4472 1426 l 4491 1435 l 4510 1443 l 4528 1452 l + 4545 1460 l 4561 1468 l 4576 1476 l 4596 1487 l 4616 1499 l + 4634 1511 l 4652 1523 l 4669 1535 l 4686 1547 l 4701 1560 l + 4715 1572 l 4728 1583 l 4740 1594 l 4751 1604 l 4760 1614 l + 4769 1623 l 4777 1631 l 4787 1642 l 4797 1653 l 4807 1663 l + 4817 1672 l 4827 1681 l 4836 1689 l 4846 1696 l 4855 1701 l + 4864 1705 l 4874 1709 l 4882 1711 l 4891 1712 l 4902 1713 l + 4913 1713 l 4925 1712 l 4938 1710 l 4952 1708 l 4966 1705 l + 4981 1701 l 4996 1697 l 5011 1692 l 5026 1686 l 5040 1681 l + 5055 1675 l 5070 1668 l 5086 1661 l 5103 1653 l 5120 1644 l + 5136 1636 l 5153 1627 l 5169 1618 l 5184 1609 l 5198 1601 l + 5210 1593 l 5221 1585 l 5231 1578 l 5241 1570 l 5250 1562 l + 5258 1553 l 5264 1545 l 5270 1536 l 5274 1526 l 5278 1516 l + 5280 1505 l 5282 1494 l 5283 1483 l 5284 1471 l 5284 1459 l + 5285 1447 l 5285 1434 l 5284 1420 l 5284 1405 l 5283 1388 l + 5282 1371 l 5281 1353 l 5279 1335 l 5277 1316 l 5274 1298 l + 5271 1280 l 5267 1263 l 5263 1246 l 5259 1230 l 5254 1214 l + 5248 1198 l 5241 1181 l 5234 1165 l 5227 1148 l 5219 1131 l + 5210 1115 l 5202 1098 l 5193 1083 l 5185 1069 l 5178 1055 l + 5170 1043 l 5164 1031 l 5158 1021 l 5150 1007 l 5143 993 l + 5136 981 l 5131 969 l 5126 957 l 5123 947 l 5121 938 l + 5120 929 l 5121 922 l 5122 916 l 5125 910 l 5129 905 l + 5135 899 l 5141 894 l 5149 890 l 5158 886 l 5167 883 l + 5177 880 l 5187 879 l 5197 878 l 5208 877 l 5219 877 l + 5232 878 l 5245 880 l 5259 883 l 5273 887 l 5287 891 l + 5300 896 l 5314 902 l 5326 908 l 5335 913 l 5345 918 l + 5354 925 l 5365 932 l 5375 940 l 5386 949 l 5398 958 l + 5410 969 l 5422 980 l 5434 992 l 5446 1004 l 5458 1016 l + 5470 1030 l 5482 1044 l 5492 1055 l 5502 1067 l 5513 1080 l + 5524 1093 l 5536 1108 l 5548 1123 l 5560 1139 l 5573 1155 l + 5585 1172 l 5598 1189 l 5610 1206 l 5622 1223 l 5633 1240 l + 5644 1256 l 5654 1272 l 5663 1287 l 5673 1302 l 5681 1317 l + 5690 1333 l 5699 1349 l 5707 1365 l 5715 1382 l 5723 1399 l + 5730 1416 l 5737 1434 l 5744 1451 l 5750 1468 l 5756 1485 l + 5762 1502 l 5767 1518 l 5771 1534 l 5776 1549 l 5780 1563 l + 5783 1578 l 5787 1592 l 5790 1607 l 5794 1622 l 5797 1637 l + 5800 1653 l 5804 1670 l 5806 1687 l 5809 1704 l 5811 1721 l + 5813 1738 l 5815 1754 l 5816 1771 l 5817 1786 l 5817 1802 l + 5817 1817 l 5816 1832 l 5815 1847 l 5814 1862 l 5812 1877 l + 5810 1893 l 5807 1910 l 5803 1928 l 5799 1945 l 5794 1964 l + 5788 1982 l 5782 2000 l 5775 2019 l 5768 2037 l 5760 2055 l + 5752 2072 l 5744 2089 l 5735 2107 l 5726 2122 l 5717 2138 l + 5707 2155 l 5697 2172 l 5686 2190 l 5674 2208 l 5661 2227 l + 5647 2245 l 5634 2264 l 5619 2283 l 5605 2302 l 5590 2320 l + 5576 2338 l 5561 2355 l 5547 2371 l 5532 2387 l 5518 2402 l + 5504 2417 l 5490 2431 l 5475 2445 l 5460 2458 l 5445 2472 l + 5429 2486 l 5412 2500 l 5396 2514 l 5379 2527 l 5362 2540 l + 5346 2553 l 5330 2566 l 5314 2577 l 5299 2589 l 5284 2599 l + 5270 2609 l 5257 2618 l 5245 2627 l 5233 2636 l 5216 2648 l + 5199 2659 l 5183 2671 l 5168 2681 l 5153 2692 l 5139 2701 l + 5126 2710 l 5115 2718 l 5105 2724 l 5097 2730 l 5090 2734 l + 5085 2737 l 5081 2739 l 5078 2741 l 5075 2743 l 5073 2744 l + 5072 2746 l 5071 2747 l 5070 2750 l 5070 2753 l 5070 2756 l + 5071 2761 l 5071 2766 l 5072 2772 l 5073 2780 l 5073 2789 l + 5074 2798 l 5074 2809 l 5074 2821 l 5074 2834 l 5074 2849 l + 5074 2865 l 5073 2883 l 5073 2901 l 5072 2921 l 5070 2940 l + 5069 2960 l 5067 2979 l 5066 2999 l 5064 3018 l 5061 3036 l + 5059 3055 l 5056 3073 l 5053 3092 l 5050 3111 l 5046 3130 l + 5042 3150 l 5037 3170 l 5032 3190 l 5026 3211 l 5021 3231 l + 5015 3251 l 5008 3270 l 5002 3289 l 4996 3307 l 4989 3324 l + 4982 3340 l 4976 3356 l 4968 3372 l 4961 3387 l 4953 3403 l + 4944 3419 l 4935 3436 l 4925 3452 l 4915 3469 l 4904 3486 l + 4893 3503 l 4882 3519 l 4870 3535 l 4859 3550 l 4847 3565 l + 4835 3580 l 4823 3594 l 4812 3608 l 4799 3622 l 4786 3636 l + 4773 3650 l 4759 3665 l 4744 3680 l 4730 3695 l 4714 3710 l + 4699 3726 l 4684 3741 l 4670 3756 l 4656 3770 l 4643 3783 l + 4630 3796 l 4619 3808 l 4608 3819 l 4599 3830 l 4587 3843 l + 4576 3856 l 4565 3869 l 4556 3882 l 4547 3895 l 4539 3907 l + 4532 3919 l 4526 3930 l 4521 3941 l 4517 3951 l 4513 3961 l + 4510 3970 l 4506 3981 l 4503 3992 l 4501 4004 l 4498 4016 l + 4496 4029 l 4494 4042 l 4493 4054 l 4493 4066 l 4493 4078 l + 4493 4089 l 4493 4100 l 4494 4112 l 4496 4124 l 4498 4137 l + 4501 4150 l 4504 4164 l 4507 4177 l 4511 4189 l 4515 4200 l + 4520 4212 l 4525 4223 l 4530 4234 l 4537 4246 l 4543 4259 l + 4551 4272 l 4558 4284 l 4565 4297 l 4572 4309 l 4579 4320 l + 4585 4331 l 4591 4343 l 4597 4354 l 4603 4367 l 4609 4380 l + 4615 4394 l 4621 4408 l 4626 4422 l 4631 4436 l 4636 4450 l + 4640 4464 l 4643 4474 l 4646 4485 l 4649 4496 l 4652 4508 l + 4654 4521 l 4657 4534 l 4660 4549 l 4663 4563 l 4665 4579 l + 4667 4594 l 4669 4610 l 4671 4625 l 4673 4641 l 4675 4658 l + 4676 4672 l 4677 4688 l 4678 4704 l 4679 4721 l 4680 4739 l + 4681 4757 l 4682 4776 l 4682 4795 l 4683 4814 l 4683 4832 l + 4683 4851 l 4684 4868 l 4684 4884 l 4683 4900 l 4683 4915 l + 4683 4929 l 4682 4946 l 4682 4963 l 4681 4980 l 4679 4996 l + 4678 5012 l 4676 5028 l 4674 5043 l 4671 5056 l 4669 5069 l + 4666 5081 l 4663 5092 l 4661 5103 l 4657 5115 l 4652 5128 l + 4648 5141 l 4643 5154 l 4638 5168 l 4633 5181 l 4628 5194 l + 4624 5206 l 4621 5218 l 4618 5229 l 4616 5238 l 4615 5247 l + 4614 5257 l 4613 5268 l 4613 5280 l 4614 5292 l 4616 5305 l + 4618 5319 l 4620 5334 l 4624 5349 l 4628 5365 l 4632 5382 l + 4636 5395 l 4640 5410 l 4645 5425 l 4650 5442 l 4656 5460 l + 4663 5479 l 4670 5498 l 4677 5519 l 4685 5540 l 4693 5560 l + 4702 5581 l 4710 5602 l 4719 5621 l 4728 5641 l 4737 5660 l + 4746 5678 l 4754 5694 l 4762 5711 l 4771 5727 l 4780 5744 l + 4790 5762 l 4801 5779 l 4812 5797 l 4823 5814 l 4834 5832 l + 4846 5849 l 4859 5866 l 4871 5883 l 4883 5899 l 4895 5914 l + 4908 5929 l 4920 5943 l 4932 5957 l 4944 5970 l 4957 5983 l + 4970 5996 l 4984 6009 l 4998 6021 l 5013 6034 l 5028 6048 l + 5044 6061 l 5061 6074 l 5078 6087 l 5095 6099 l 5113 6112 l + 5130 6124 l 5147 6135 l 5164 6146 l 5181 6156 l 5198 6167 l + 5214 6176 l 5230 6186 l 5247 6195 l 5264 6204 l 5281 6213 l + 5299 6222 l 5318 6232 l 5337 6241 l 5357 6250 l 5378 6260 l + 5399 6269 l 5420 6278 l 5441 6287 l 5462 6295 l 5483 6303 l + 5503 6311 l 5523 6318 l 5543 6325 l 5563 6332 l 5582 6338 l + 5600 6344 l 5618 6350 l 5637 6355 l 5656 6361 l 5676 6366 l + 5697 6372 l 5718 6377 l 5740 6383 l 5762 6389 l 5785 6394 l + 5807 6400 l 5830 6405 l 5853 6410 l 5875 6416 l 5898 6421 l + 5919 6425 l 5941 6430 l 5962 6435 l 5983 6439 l 6004 6444 l + 6025 6448 l 6046 6453 l 6068 6457 l 6090 6462 l 6113 6467 l + 6136 6472 l 6160 6477 l 6185 6482 l 6209 6487 l 6233 6492 l + 6258 6497 l 6282 6502 l 6305 6507 l 6328 6512 l 6350 6517 l + 6371 6522 l 6391 6526 l 6411 6531 l 6430 6535 l 6448 6539 l + 6470 6544 l 6491 6549 l 6513 6555 l 6535 6560 l 6556 6565 l + 6578 6571 l 6599 6576 l 6620 6582 l 6640 6587 l 6659 6593 l + 6678 6598 l 6695 6603 l 6712 6608 l 6727 6613 l 6742 6618 l + 6756 6622 l 6772 6627 l 6788 6632 l 6803 6638 l 6819 6643 l + 6835 6649 l 6851 6655 l 6867 6662 l 6882 6668 l 6897 6674 l + 6912 6681 l 6925 6687 l 6938 6694 l 6951 6700 l 6963 6707 l + 6975 6713 l 6987 6721 l 7000 6728 l 7012 6736 l 7025 6745 l + 7038 6754 l 7051 6763 l 7063 6773 l 7075 6783 l 7086 6792 l + 7096 6802 l 7106 6811 l 7115 6820 l 7123 6829 l 7132 6840 l + 7140 6851 l 7148 6863 l 7156 6875 l 7163 6888 l 7170 6901 l + 7176 6914 l 7181 6927 l 7186 6940 l 7189 6951 l 7193 6963 l + 7196 6974 l 7198 6987 l 7200 7000 l 7202 7014 l 7203 7029 l + 7202 7043 l 7201 7058 l 7198 7072 l 7194 7086 l 7189 7099 l + 7183 7111 l 7177 7122 l 7170 7132 l 7162 7144 l 7153 7155 l + 7143 7167 l 7132 7179 l 7120 7190 l 7108 7201 l 7097 7211 l + 7085 7221 l 7074 7230 l 7063 7238 l 7054 7245 l 7044 7252 l + 7034 7258 l 7023 7265 l 7012 7271 l 6999 7277 l 6986 7284 l + 6973 7290 l 6958 7295 l 6943 7301 l 6928 7306 l 6912 7311 l + 6895 7316 l 6878 7321 l 6862 7325 l 6844 7330 l 6826 7334 l + 6806 7339 l 6786 7343 l 6764 7348 l 6742 7352 l 6720 7357 l + 6699 7361 l 6677 7366 l 6657 7370 l 6638 7373 l 6620 7377 l + 6604 7380 l 6589 7383 l 6576 7385 l 6560 7388 l 6546 7391 l + 6534 7393 l 6524 7396 l 6515 7398 l 6507 7400 l 6502 7403 l + 6498 7405 l 6495 7408 l 6493 7411 l 6493 7414 l 6493 7417 l + 6494 7425 l 6496 7436 l 6499 7448 l 6502 7460 l 6504 7471 l + 6504 7480 l 6502 7484 l 6500 7487 l 6497 7491 l 6491 7493 l + 6484 7495 l 6475 7497 l 6464 7499 l 6450 7500 l 6435 7500 l + 6418 7501 l 6408 7501 l 6396 7502 l 6384 7502 l 6370 7502 l + 6355 7502 l 6338 7503 l 6321 7503 l 6302 7503 l 6282 7504 l + 6262 7504 l 6241 7505 l 6219 7505 l 6198 7505 l 6176 7506 l + 6154 7506 l 6131 7507 l 6109 7507 l 6087 7508 l 6066 7509 l + 6044 7509 l 6022 7510 l 5999 7511 l 5975 7511 l 5951 7512 l + 5925 7513 l 5900 7514 l 5873 7515 l 5847 7516 l 5821 7517 l + 5795 7518 l 5770 7519 l 5745 7520 l 5722 7521 l 5699 7522 l + 5677 7523 l 5656 7524 l 5636 7525 l 5617 7526 l 5594 7527 l + 5571 7528 l 5549 7530 l 5528 7531 l 5506 7532 l 5485 7533 l + 5465 7535 l 5446 7536 l 5428 7537 l 5410 7538 l 5394 7539 l + 5380 7539 l 5367 7540 l 5355 7540 l 5344 7541 l 5334 7541 l + 5320 7541 l 5307 7541 l 5296 7540 l 5286 7539 l 5277 7538 l + 5270 7536 l 5266 7534 l 5262 7532 l 5261 7530 l 5260 7527 l + 5260 7525 l 5262 7522 l 5265 7518 l 5270 7514 l 5277 7508 l + 5286 7502 l 5298 7494 l 5313 7485 l 5330 7474 l 5350 7462 l + 5373 7449 l 5399 7435 l 5414 7426 l 5431 7417 l 5449 7407 l + 5468 7396 l 5488 7385 l 5510 7373 l 5533 7361 l 5556 7348 l + 5581 7334 l 5606 7321 l 5632 7306 l 5657 7292 l 5683 7278 l + 5708 7264 l 5733 7251 l 5758 7237 l 5781 7224 l 5804 7212 l + 5825 7200 l 5846 7189 l 5865 7178 l 5884 7168 l 5908 7154 l + 5932 7141 l 5954 7128 l 5975 7116 l 5996 7104 l 6016 7092 l + 6035 7081 l 6052 7071 l 6069 7061 l 6084 7052 l 6098 7043 l + 6111 7035 l 6122 7028 l 6133 7021 l 6142 7015 l 6151 7010 l + 6163 7001 l 6175 6993 l 6187 6985 l 6197 6977 l 6207 6971 l + 6217 6965 l 6225 6961 l 6232 6958 l 6238 6956 l 6244 6956 l + 6249 6956 l 6254 6957 l 6259 6960 l 6264 6964 l 6269 6968 l + 6274 6974 l 6279 6980 l 6284 6986 l 6288 6992 l 6293 6999 l + 6298 7007 l 6304 7016 l 6310 7026 l 6316 7036 l 6322 7046 l + 6328 7057 l 6333 7066 l 6338 7076 l 6342 7085 l 6346 7095 l + 6351 7105 l 6355 7115 l 6359 7125 l 6363 7134 l 6367 7142 l + 6370 7150 l 6373 7156 l 6377 7162 l 6381 7167 l 6386 7172 l + 6392 7177 l 6399 7182 l 6406 7185 l 6415 7188 l 6424 7190 l + 6435 7191 l 6444 7191 l 6455 7191 l 6467 7190 l 6481 7189 l + 6495 7187 l 6510 7185 l 6526 7183 l 6542 7180 l 6557 7177 l + 6572 7173 l 6586 7170 l 6599 7167 l 6613 7163 l 6626 7159 l + 6639 7155 l 6653 7151 l 6667 7146 l 6680 7141 l 6694 7136 l + 6706 7131 l 6719 7126 l 6730 7121 l 6741 7116 l 6752 7111 l + 6764 7104 l 6776 7098 l 6789 7090 l 6801 7083 l 6813 7075 l + 6825 7066 l 6835 7058 l 6844 7050 l 6851 7043 l 6857 7036 l + 6861 7030 l 6864 7024 l 6867 7017 l 6869 7010 l 6870 7004 l + 6870 6996 l 6869 6989 l 6867 6982 l 6865 6975 l 6862 6968 l + 6858 6961 l 6853 6954 l 6848 6947 l 6842 6939 l 6835 6931 l + 6826 6923 l 6817 6914 l 6807 6905 l 6796 6896 l 6784 6888 l + 6773 6879 l 6761 6871 l 6748 6864 l 6736 6857 l 6726 6852 l + 6716 6847 l 6705 6842 l 6694 6837 l 6681 6831 l 6667 6826 l + 6652 6821 l 6636 6816 l 6620 6811 l 6602 6806 l 6584 6801 l + 6565 6797 l 6546 6792 l 6526 6788 l 6506 6784 l 6485 6780 l + 6467 6777 l 6448 6774 l 6428 6770 l 6407 6767 l 6384 6764 l + 6361 6760 l 6337 6757 l 6312 6753 l 6286 6749 l 6259 6746 l + 6232 6742 l 6206 6738 l 6179 6735 l 6153 6731 l 6127 6728 l + 6102 6724 l 6078 6721 l 6054 6717 l 6031 6714 l 6009 6711 l + 5986 6707 l 5964 6704 l 5942 6700 l 5920 6696 l 5897 6693 l + 5874 6689 l 5851 6685 l 5828 6681 l 5805 6676 l 5783 6672 l + 5760 6668 l 5738 6664 l 5717 6660 l 5696 6655 l 5676 6651 l + 5657 6647 l 5639 6644 l 5622 6640 l 5605 6636 l 5588 6633 l + 5568 6628 l 5547 6623 l 5527 6619 l 5507 6614 l 5486 6609 l + 5465 6603 l 5444 6598 l 5423 6593 l 5402 6587 l 5382 6582 l + 5363 6577 l 5344 6571 l 5326 6566 l 5309 6561 l 5292 6557 l + 5276 6552 l 5260 6547 l 5243 6542 l 5227 6537 l 5210 6531 l + 5192 6526 l 5175 6520 l 5157 6514 l 5140 6508 l 5122 6502 l + 5105 6496 l 5089 6491 l 5073 6485 l 5058 6480 l 5044 6475 l + 5030 6470 l 5017 6465 l 5003 6460 l 4988 6454 l 4974 6449 l + 4959 6443 l 4944 6437 l 4929 6431 l 4915 6425 l 4900 6419 l + 4887 6413 l 4873 6407 l 4861 6401 l 4849 6395 l 4838 6389 l + 4827 6383 l 4814 6375 l 4801 6368 l 4788 6360 l 4775 6351 l + 4762 6342 l 4748 6333 l 4735 6324 l 4722 6315 l 4710 6306 l + 4698 6298 l 4687 6290 l 4676 6283 l 4666 6275 l 4655 6268 l + 4644 6260 l 4633 6252 l 4621 6244 l 4610 6236 l 4598 6227 l + 4587 6219 l 4577 6211 l 4566 6203 l 4557 6195 l 4547 6187 l + 4536 6177 l 4525 6167 l 4513 6156 l 4501 6145 l 4490 6133 l + 4478 6123 l 4467 6113 l 4457 6105 l 4448 6098 l 4440 6093 l + 4433 6089 l 4427 6086 l 4419 6085 l 4410 6084 l 4400 6086 l + 4388 6088 l 4373 6092 l 4356 6097 l 4337 6104 l 4316 6113 l + 4292 6122 l 4265 6133 l 4250 6139 l 4234 6146 l 4217 6153 l + 4198 6160 l 4179 6167 l 4158 6175 l 4136 6183 l 4112 6191 l + 4088 6199 l 4062 6207 l 4036 6215 l 4009 6223 l 3982 6230 l + 3954 6237 l 3926 6243 l 3897 6248 l 3869 6253 l 3841 6257 l + 3814 6261 l 3787 6263 l 3760 6265 l 3733 6265 l 3707 6265 l + 3681 6264 l 3655 6261 l 3629 6258 l 3603 6254 l 3577 6248 l + 3550 6242 l 3523 6235 l 3496 6227 l 3469 6218 l 3441 6208 l + 3414 6198 l 3387 6187 l 3361 6176 l 3335 6165 l 3310 6153 l + 3286 6141 l 3263 6130 l 3242 6118 l 3221 6107 l 3201 6096 l + 3183 6085 l 3166 6075 l 3151 6066 l 3136 6057 l 3123 6048 l + 3102 6035 l 3083 6022 l 3067 6011 l 3052 6000 l 3039 5990 l + 3028 5980 l 3019 5971 l 3010 5963 l 3003 5955 l 2997 5947 l + 2992 5939 l 2987 5932 l 2982 5924 l 2977 5916 l 2972 5907 l + 2966 5897 l 2959 5886 l 2952 5874 l 2944 5862 l 2936 5849 l + 2927 5835 l 2918 5821 l 2910 5807 l 2902 5793 l 2894 5780 l + 2886 5767 l 2879 5755 l 2873 5744 l 2865 5730 l 2858 5717 l + 2852 5704 l 2845 5690 l 2839 5676 l 2834 5663 l 2828 5649 l + 2824 5636 l 2820 5624 l 2816 5612 l 2813 5600 l 2811 5589 l + 2809 5578 l 2807 5566 l 2805 5554 l 2804 5541 l 2803 5528 l + 2802 5515 l 2801 5502 l 2801 5489 l 2801 5477 l 2801 5465 l + 2802 5454 l 2802 5444 l 2803 5431 l 2805 5418 l 2806 5406 l + 2808 5392 l 2810 5379 l 2813 5366 l 2816 5354 l 2819 5343 l + 2822 5332 l 2825 5322 l 2830 5309 l 2835 5297 l 2840 5284 l + 2846 5271 l 2852 5259 l 2857 5248 l 2862 5239 l 2866 5231 l + 2870 5221 l 2874 5212 l 2876 5205 l 2877 5197 l 2878 5191 l + 2877 5186 l 2875 5181 l 2872 5175 l 2867 5168 l 2862 5161 l + 2855 5154 l 2848 5146 l 2841 5139 l 2834 5131 l 2826 5122 l + 2817 5113 l 2809 5103 l 2802 5093 l 2795 5083 l 2789 5074 l + 2785 5064 l 2781 5054 l 2778 5043 l 2775 5032 l 2774 5022 l + 2773 5012 l 2773 5003 l 2774 4995 l 2774 4988 l 2776 4981 l + 2777 4974 l 2778 4968 l 2778 4962 l 2777 4957 l 2775 4953 l + 2772 4951 l 2766 4948 l 2756 4945 l 2745 4944 l 2732 4942 l + 2720 4941 l 2709 4940 l 2700 4938 l 2691 4936 l 2682 4933 l + 2675 4929 l 2668 4925 l 2663 4921 l 2658 4916 l 2652 4910 l + 2647 4904 l 2641 4898 l 2635 4892 l 2628 4888 l 2624 4885 l + 2620 4882 l 2614 4878 l 2607 4873 l 2599 4866 l 2589 4857 l + 2578 4846 l 2565 4832 l 2551 4816 l 2536 4796 l 2526 4784 l + 2516 4770 l 2505 4755 l 2493 4739 l 2481 4722 l 2469 4703 l + 2456 4683 l 2443 4663 l 2431 4643 l 2418 4622 l 2407 4601 l + 2396 4580 l 2386 4561 l 2377 4542 l 2369 4524 l 2363 4507 l + 2358 4491 l 2354 4476 l 2352 4463 l 2351 4451 l 2351 4439 l + 2352 4428 l 2354 4417 l 2357 4407 l 2361 4397 l 2366 4388 l + 2372 4379 l 2379 4370 l 2387 4362 l 2395 4355 l 2404 4348 l + 2414 4342 l 2424 4337 l 2434 4331 l 2445 4327 l 2455 4323 l + 2466 4319 l 2477 4315 l 2492 4311 l 2507 4307 l 2522 4304 l + 2539 4301 l 2556 4298 l 2574 4295 l 2592 4292 l 2611 4290 l + 2630 4288 l 2649 4287 l 2668 4285 l 2686 4284 l 2703 4284 l + 2720 4283 l 2736 4283 l 2752 4283 l 2769 4284 l 2787 4284 l + 2805 4285 l 2823 4286 l 2841 4287 l 2860 4289 l 2878 4291 l + 2895 4292 l 2912 4294 l 2928 4296 l 2943 4298 l 2957 4300 l + 2970 4302 l 2983 4304 l 2999 4306 l 3015 4308 l 3030 4311 l + 3046 4312 l 3061 4314 l 3075 4314 l 3088 4314 l 3099 4313 l + 3110 4311 l 3119 4308 l 3128 4304 l 3137 4299 l 3146 4292 l + 3155 4285 l 3163 4276 l 3170 4267 l 3177 4257 l 3183 4248 l + 3188 4238 l 3193 4229 l 3196 4219 l 3200 4209 l 3203 4199 l + 3205 4188 l 3207 4177 l 3208 4166 l 3208 4155 l 3208 4145 l + 3208 4135 l 3207 4126 l 3205 4114 l 3201 4102 l 3197 4090 l + 3192 4078 l 3186 4066 l 3179 4056 l 3172 4046 l 3165 4039 l + 3157 4031 l 3147 4025 l 3137 4019 l 3126 4013 l 3114 4007 l + 3102 4002 l 3091 3997 l 3081 3992 l 3072 3988 l 3063 3984 l + 3053 3979 l 3043 3974 l 3033 3969 l 3023 3963 l 3013 3957 l + 3003 3950 l 2993 3944 l 2984 3938 l 2975 3931 l 2965 3923 l + 2955 3915 l 2943 3906 l 2932 3897 l 2920 3888 l 2908 3879 l + 2896 3870 l 2885 3861 l 2873 3853 l 2863 3846 l 2853 3840 l + 2842 3833 l 2831 3826 l 2819 3818 l 2807 3811 l 2795 3804 l + 2783 3797 l 2771 3790 l 2761 3784 l 2751 3777 l 2741 3772 l + 2730 3764 l 2719 3757 l 2707 3750 l 2696 3743 l 2684 3735 l + 2672 3728 l 2660 3721 l 2649 3715 l 2638 3710 l 2627 3705 l + 2618 3701 l 2608 3697 l 2597 3693 l 2586 3689 l 2574 3685 l + 2562 3681 l 2550 3677 l 2537 3672 l 2525 3668 l 2513 3663 l + 2501 3659 l 2490 3654 l 2478 3649 l 2466 3643 l 2454 3636 l + 2441 3629 l 2428 3621 l 2414 3613 l 2401 3604 l 2388 3595 l + 2375 3585 l 2363 3576 l 2352 3567 l 2342 3557 l 2331 3547 l + 2321 3537 l 2311 3526 l 2300 3514 l 2290 3502 l 2280 3490 l + 2270 3477 l 2261 3465 l 2252 3454 l 2244 3443 l 2237 3433 l + 2231 3424 l 2223 3413 l 2216 3402 l 2209 3391 l 2202 3380 l + 2195 3368 l 2189 3357 l 2184 3346 l 2178 3335 l 2174 3325 l + 2170 3314 l 2166 3303 l 2162 3291 l 2158 3278 l 2154 3265 l + 2151 3251 l 2148 3237 l 2145 3223 l 2142 3211 l 2141 3199 l + 2139 3188 l 2138 3177 l 2137 3166 l 2136 3156 l 2136 3145 l + 2136 3133 l 2136 3122 l 2137 3112 l 2138 3101 l 2140 3092 l + 2141 3082 l 2143 3072 l 2145 3061 l 2148 3049 l 2151 3037 l + 2154 3025 l 2158 3012 l 2162 3000 l 2166 2988 l 2170 2977 l + + cp gs col20 1.00 shd ef gr gs col0 s gr +% Polyline +n 2420 6449 m 2432 6448 l 2444 6448 l 2457 6447 l 2471 6446 l 2484 6446 l + 2498 6445 l 2511 6445 l 2524 6445 l 2536 6445 l 2548 6445 l + 2560 6444 l 2572 6444 l 2584 6444 l 2597 6444 l 2610 6444 l + 2623 6444 l 2635 6444 l 2647 6444 l 2658 6444 l 2669 6444 l + 2679 6443 l 2689 6443 l 2700 6443 l 2711 6442 l 2722 6441 l + 2733 6440 l 2743 6439 l 2752 6437 l 2761 6435 l 2770 6433 l + 2780 6429 l 2790 6424 l 2801 6419 l 2812 6413 l 2822 6407 l + 2833 6401 l 2843 6396 l 2854 6391 l 2864 6386 l 2875 6382 l + 2887 6377 l 2900 6372 l 2913 6368 l 2925 6364 l 2936 6360 l + 2947 6356 l 2957 6352 l 2967 6348 l 2977 6344 l 2987 6339 l + 2997 6335 l 3006 6330 l 3013 6326 l 3021 6323 l 3029 6318 l + 3037 6312 l 3045 6306 l 3051 6300 l 3056 6292 l 3060 6285 l + 3061 6278 l 3062 6270 l 3062 6261 l 3062 6251 l 3061 6241 l + 3059 6232 l 3057 6223 l 3055 6215 l 3052 6207 l 3049 6198 l + 3046 6190 l 3042 6181 l 3038 6173 l 3034 6164 l 3030 6156 l + 3027 6148 l 3023 6139 l 3019 6129 l 3015 6119 l 3011 6108 l + 3008 6096 l 3004 6086 l 3001 6075 l 2999 6066 l 2995 6054 l + 2992 6041 l 2990 6029 l 2989 6018 l 2989 6009 l 2990 6003 l + 2991 6000 l 2992 5998 l 2995 5996 l 2997 5994 l 3001 5994 l + 3004 5993 l 3008 5994 l 3012 5995 l 3017 5996 l 3021 5998 l + 3029 6001 l 3037 6006 l 3047 6012 l 3057 6018 l 3065 6025 l + 3073 6031 l 3080 6038 l 3088 6044 l 3095 6051 l 3103 6057 l + 3110 6062 l 3118 6065 l 3126 6066 l 3136 6066 l 3147 6065 l + 3158 6064 l 3169 6062 l 3180 6061 l 3188 6060 l 3197 6059 l + 3206 6059 l 3215 6059 l 3224 6059 l 3233 6059 l 3241 6060 l + 3249 6060 l 3258 6060 l 3268 6061 l 3279 6062 l 3289 6064 l + 3297 6066 l 3305 6068 l 3312 6071 l 3320 6075 l 3327 6081 l + 3335 6087 l 3342 6093 l 3348 6100 l 3355 6106 l 3362 6114 l + 3370 6122 l 3378 6129 l 3387 6134 l 3395 6138 l 3404 6140 l + 3413 6140 l 3424 6140 l 3434 6138 l 3443 6137 l 3452 6136 l + 3460 6135 l 3468 6134 l 3477 6135 l 3484 6137 l 3491 6139 l + 3496 6143 l 3501 6148 l 3505 6154 l 3510 6162 l 3514 6171 l + 3517 6180 l 3520 6189 l 3522 6196 l 3524 6204 l 3526 6212 l + 3528 6221 l 3530 6229 l 3532 6238 l 3533 6245 l 3534 6253 l + 3535 6262 l 3536 6271 l 3538 6279 l 3539 6285 l 3541 6288 l + 3543 6288 l 3545 6285 l 3548 6279 l 3552 6270 l 3556 6259 l + 3560 6247 l 3564 6236 l 3567 6227 l 3571 6218 l 3574 6208 l + 3578 6198 l 3582 6188 l 3586 6178 l 3590 6169 l 3594 6161 l + 3598 6152 l 3602 6143 l 3607 6134 l 3612 6126 l 3617 6117 l + 3623 6109 l 3628 6103 l 3634 6097 l 3639 6091 l 3646 6086 l + 3653 6081 l 3661 6076 l 3670 6072 l 3678 6069 l 3686 6066 l + 3694 6064 l 3701 6062 l 3710 6060 l 3719 6059 l 3728 6058 l + 3737 6057 l 3746 6057 l 3755 6057 l 3763 6058 l 3770 6058 l + 3778 6059 l 3787 6061 l 3795 6063 l 3804 6065 l 3812 6068 l + 3820 6070 l 3828 6074 l 3835 6077 l 3843 6081 l 3851 6086 l + 3860 6091 l 3869 6096 l 3877 6102 l 3885 6107 l 3893 6112 l + 3900 6117 l 3908 6123 l 3916 6129 l 3924 6135 l 3931 6141 l + 3938 6147 l 3944 6153 l 3950 6159 l 3956 6166 l 3962 6173 l + 3967 6179 l 3971 6184 l 3974 6188 l 3977 6189 l 3979 6187 l + 3981 6182 l 3983 6175 l 3986 6168 l 3989 6161 l 3992 6157 l + 3995 6154 l 3999 6151 l 4004 6148 l 4010 6146 l 4016 6144 l + 4023 6142 l 4030 6141 l 4038 6140 l 4046 6139 l 4056 6139 l + 4067 6138 l 4078 6138 l 4089 6138 l 4099 6137 l 4110 6137 l + 4120 6137 l 4131 6136 l 4142 6135 l 4154 6134 l 4166 6133 l + 4177 6132 l 4188 6130 l 4198 6128 l 4208 6126 l 4218 6123 l + 4229 6120 l 4240 6117 l 4251 6113 l 4261 6110 l 4271 6107 l + 4280 6104 l 4288 6101 l 4296 6098 l 4305 6095 l 4314 6091 l + 4323 6088 l 4332 6085 l 4340 6081 l 4348 6078 l 4356 6074 l + 4365 6071 l 4374 6067 l 4383 6064 l 4392 6062 l 4401 6062 l + 4409 6063 l 4416 6066 l 4423 6070 l 4429 6077 l 4436 6086 l + 4443 6097 l 4450 6109 l 4456 6122 l 4462 6134 l 4468 6147 l + 4473 6157 l 4478 6168 l 4483 6180 l 4489 6192 l 4495 6205 l + 4501 6218 l 4507 6231 l 4513 6243 l 4518 6255 l 4524 6267 l + 4528 6277 l 4533 6287 l 4537 6298 l 4542 6310 l 4548 6321 l + 4553 6334 l 4558 6346 l 4563 6358 l 4567 6370 l 4572 6381 l + 4576 6392 l 4580 6403 l 4584 6414 l 4588 6425 l 4592 6437 l + 4596 6449 l 4600 6461 l 4604 6474 l 4608 6486 l 4611 6498 l + 4615 6510 l 4618 6521 l 4622 6531 l 4625 6542 l 4629 6553 l + 4633 6565 l 4637 6578 l 4641 6590 l 4645 6602 l 4649 6614 l + 4653 6625 l 4657 6635 l 4660 6644 l 4663 6653 l 4665 6660 l + 4667 6668 l 4669 6675 l 4670 6682 l 4670 6690 l 4669 6698 l + 4667 6705 l 4663 6713 l 4659 6720 l 4653 6728 l 4647 6734 l + 4641 6740 l 4633 6747 l 4625 6755 l 4614 6763 l 4602 6771 l + 4589 6781 l 4574 6790 l 4558 6800 l 4540 6810 l 4522 6820 l + 4503 6831 l 4482 6841 l 4461 6852 l 4447 6858 l 4431 6866 l + 4415 6873 l 4398 6880 l 4380 6888 l 4361 6896 l 4341 6905 l + 4320 6913 l 4299 6922 l 4276 6931 l 4253 6940 l 4230 6949 l + 4206 6957 l 4183 6966 l 4159 6974 l 4136 6982 l 4112 6990 l + 4089 6997 l 4067 7004 l 4045 7011 l 4022 7018 l 4001 7024 l + 3979 7030 l 3956 7036 l 3934 7042 l 3910 7047 l 3887 7053 l + 3862 7058 l 3837 7063 l 3812 7068 l 3786 7073 l 3759 7078 l + 3732 7083 l 3705 7087 l 3679 7091 l 3652 7095 l 3625 7098 l + 3599 7102 l 3573 7105 l 3547 7107 l 3522 7110 l 3497 7112 l + 3473 7114 l 3448 7116 l 3425 7118 l 3402 7119 l 3378 7120 l + 3354 7121 l 3330 7122 l 3305 7123 l 3279 7124 l 3253 7125 l + 3226 7125 l 3199 7125 l 3172 7126 l 3146 7126 l 3119 7125 l + 3092 7125 l 3066 7125 l 3041 7124 l 3016 7123 l 2992 7123 l + 2969 7122 l 2947 7121 l 2925 7119 l 2904 7118 l 2884 7117 l + 2865 7115 l 2839 7113 l 2814 7110 l 2790 7107 l 2765 7104 l + 2741 7101 l 2717 7097 l 2693 7092 l 2669 7087 l 2646 7082 l + 2624 7077 l 2603 7071 l 2582 7065 l 2563 7058 l 2545 7051 l + 2527 7044 l 2511 7037 l 2496 7030 l 2481 7022 l 2467 7014 l + 2453 7005 l 2438 6996 l 2424 6986 l 2410 6975 l 2396 6964 l + 2382 6952 l 2368 6939 l 2354 6926 l 2340 6913 l 2326 6899 l + 2313 6885 l 2300 6872 l 2288 6858 l 2276 6844 l 2264 6831 l + 2252 6817 l 2241 6804 l 2228 6788 l 2215 6772 l 2202 6755 l + 2188 6738 l 2175 6721 l 2162 6703 l 2149 6685 l 2137 6667 l + 2127 6650 l 2117 6633 l 2109 6617 l 2102 6602 l 2098 6588 l + 2094 6575 l 2093 6564 l 2094 6553 l 2096 6542 l 2101 6532 l + 2108 6523 l 2118 6514 l 2129 6506 l 2142 6499 l 2157 6493 l + 2173 6487 l 2189 6482 l 2205 6478 l 2221 6475 l 2236 6472 l + 2251 6470 l 2265 6468 l 2280 6465 l 2295 6463 l 2310 6461 l + 2324 6459 l 2338 6457 l 2352 6456 l 2365 6454 l 2377 6453 l + 2389 6452 l 2400 6451 l 2410 6450 l + cp gs col13 1.00 shd ef gr gs col0 s gr +% Polyline +n 2452 4170 m 2451 4170 l 2448 4167 l 2439 4160 l 2424 4149 l 2405 4135 l + 2384 4118 l 2362 4102 l 2341 4086 l 2322 4071 l 2305 4059 l + 2290 4047 l 2277 4037 l 2265 4028 l 2254 4020 l 2242 4010 l + 2230 4000 l 2218 3991 l 2206 3981 l 2195 3972 l 2184 3963 l + 2174 3954 l 2164 3946 l 2155 3939 l 2147 3932 l 2140 3926 l + 2134 3920 l 2125 3912 l 2117 3905 l 2110 3897 l 2103 3891 l + 2098 3884 l 2093 3879 l 2090 3874 l 2088 3869 l 2087 3863 l + 2087 3858 l 2089 3852 l 2091 3846 l 2095 3840 l 2098 3834 l + 2102 3829 l 2107 3822 l 2112 3815 l 2117 3807 l 2122 3798 l + 2126 3790 l 2129 3784 l 2132 3776 l 2135 3768 l 2137 3760 l + 2140 3751 l 2142 3743 l 2144 3735 l 2146 3728 l 2147 3719 l + 2149 3710 l 2150 3700 l 2151 3689 l 2152 3679 l 2152 3669 l + 2152 3660 l 2152 3651 l 2152 3641 l 2151 3630 l 2151 3619 l + 2150 3609 l 2149 3598 l 2148 3589 l 2147 3579 l 2145 3570 l + 2143 3559 l 2140 3549 l 2138 3538 l 2135 3528 l 2132 3518 l + 2129 3508 l 2126 3499 l 2123 3489 l 2119 3478 l 2114 3466 l + 2109 3455 l 2104 3444 l 2098 3434 l 2091 3424 l 2086 3416 l + 2079 3408 l 2072 3400 l 2064 3392 l 2056 3384 l 2048 3376 l + 2040 3369 l 2032 3363 l 2025 3358 l 2018 3353 l 2010 3348 l + 2002 3344 l 1994 3340 l 1988 3337 l 1982 3333 l 1979 3329 l + 1978 3326 l 1978 3321 l 1981 3316 l 1985 3310 l 1990 3302 l + 1996 3294 l 2001 3286 l 2005 3277 l 2006 3269 l 2005 3262 l + 2002 3255 l 1995 3248 l 1985 3241 l 1974 3234 l 1961 3227 l + 1948 3221 l 1935 3216 l 1923 3211 l 1912 3207 l 1901 3202 l + 1891 3198 l 1880 3194 l 1870 3190 l 1860 3185 l 1851 3182 l + 1843 3178 l 1835 3174 l 1826 3170 l 1817 3165 l 1807 3160 l + 1797 3154 l 1787 3149 l 1777 3144 l 1767 3140 l 1759 3136 l + 1750 3132 l 1741 3127 l 1730 3123 l 1720 3118 l 1709 3113 l + 1698 3109 l 1687 3104 l 1677 3099 l 1667 3095 l 1655 3089 l + 1642 3083 l 1629 3077 l 1616 3072 l 1605 3067 l 1597 3065 l + 1590 3064 l 1586 3065 l 1585 3068 l 1585 3073 l 1588 3080 l + 1593 3089 l 1599 3098 l 1605 3108 l 1612 3118 l 1619 3127 l + 1625 3135 l 1632 3144 l 1639 3153 l 1646 3162 l 1652 3171 l + 1659 3180 l 1665 3189 l 1671 3198 l 1676 3207 l 1682 3217 l + 1688 3228 l 1694 3240 l 1700 3251 l 1706 3262 l 1711 3272 l + 1716 3282 l 1721 3291 l 1725 3300 l 1730 3309 l 1735 3319 l + 1740 3329 l 1744 3340 l 1748 3350 l 1752 3360 l 1756 3372 l + 1760 3384 l 1764 3397 l 1768 3410 l 1773 3422 l 1778 3433 l + 1782 3441 l 1787 3447 l 1791 3450 l 1795 3451 l 1800 3451 l + 1805 3451 l 1810 3449 l 1816 3446 l 1821 3442 l 1826 3438 l + 1831 3434 l 1836 3430 l 1845 3423 l 1854 3416 l 1863 3410 l + 1873 3405 l 1882 3402 l 1891 3402 l 1897 3403 l 1903 3406 l + 1910 3411 l 1917 3416 l 1924 3423 l 1931 3430 l 1938 3437 l + 1944 3445 l 1951 3452 l 1958 3461 l 1965 3470 l 1972 3479 l + 1979 3489 l 1986 3498 l 1991 3507 l 1996 3516 l 2000 3525 l + 2004 3534 l 2008 3544 l 2011 3554 l 2013 3564 l 2015 3574 l + 2017 3582 l 2018 3590 l 2020 3599 l 2021 3608 l 2021 3618 l + 2021 3627 l 2021 3636 l 2020 3644 l 2018 3653 l 2016 3662 l + 2013 3672 l 2009 3681 l 2005 3690 l 2000 3698 l 1994 3704 l + 1987 3711 l 1979 3718 l 1971 3724 l 1963 3730 l 1957 3735 l + 1950 3740 l 1944 3745 l 1937 3749 l 1931 3753 l 1924 3755 l + 1918 3756 l 1912 3754 l 1905 3751 l 1897 3747 l 1889 3742 l + 1881 3736 l 1874 3730 l 1868 3725 l 1861 3719 l 1853 3713 l + 1846 3707 l 1839 3701 l 1833 3696 l 1826 3691 l 1819 3686 l + 1812 3680 l 1804 3674 l 1796 3668 l 1789 3663 l 1784 3659 l + 1778 3654 l 1771 3649 l 1764 3643 l 1757 3637 l 1749 3632 l + 1742 3627 l 1735 3622 l 1728 3616 l 1721 3611 l 1713 3605 l + 1706 3598 l 1700 3592 l 1695 3585 l 1692 3578 l 1691 3571 l + 1691 3564 l 1693 3556 l 1697 3548 l 1702 3539 l 1707 3530 l + 1712 3522 l 1717 3515 l 1721 3509 l 1722 3507 l 1723 3505 l + 1724 3502 l 1725 3500 l 1726 3498 l 1726 3496 l 1726 3494 l + 1726 3493 l 1726 3491 l 1725 3489 l 1724 3487 l 1722 3486 l + 1720 3485 l 1718 3483 l 1716 3482 l 1713 3481 l 1709 3480 l + 1706 3479 l 1702 3478 l 1697 3477 l 1689 3476 l 1679 3475 l + 1668 3473 l 1654 3471 l 1639 3469 l 1623 3466 l 1605 3462 l + 1587 3457 l 1568 3452 l 1550 3446 l 1531 3439 l 1512 3431 l + 1495 3423 l 1477 3414 l 1459 3405 l 1440 3394 l 1421 3384 l + 1402 3373 l 1383 3362 l 1365 3352 l 1349 3343 l 1334 3336 l + 1321 3329 l 1310 3325 l 1301 3322 l 1294 3321 l 1288 3322 l + 1285 3325 l 1283 3330 l 1283 3337 l 1285 3346 l 1288 3356 l + 1292 3368 l 1297 3380 l 1304 3394 l 1310 3407 l 1317 3421 l + 1324 3435 l 1332 3448 l 1339 3462 l 1346 3477 l 1354 3492 l + 1362 3507 l 1370 3523 l 1378 3538 l 1386 3554 l 1393 3569 l + 1400 3583 l 1406 3597 l 1411 3609 l 1416 3620 l 1420 3631 l + 1426 3645 l 1430 3660 l 1434 3674 l 1438 3687 l 1441 3699 l + 1443 3709 l 1446 3718 l 1448 3725 l 1450 3732 l 1452 3737 l + 1455 3743 l 1458 3747 l 1461 3751 l 1464 3754 l 1467 3755 l + 1470 3756 l 1475 3756 l 1480 3754 l 1486 3750 l 1493 3746 l + 1500 3740 l 1507 3733 l 1513 3728 l 1519 3722 l 1526 3715 l + 1533 3709 l 1541 3703 l 1548 3699 l 1555 3695 l 1562 3694 l + 1568 3693 l 1575 3695 l 1582 3697 l 1590 3702 l 1598 3707 l + 1606 3713 l 1614 3719 l 1622 3726 l 1630 3733 l 1639 3740 l + 1649 3748 l 1660 3757 l 1670 3766 l 1680 3774 l 1689 3782 l + 1698 3789 l 1706 3795 l 1714 3802 l 1721 3810 l 1729 3817 l + 1736 3825 l 1743 3833 l 1748 3840 l 1754 3848 l 1758 3856 l + 1762 3865 l 1766 3874 l 1769 3885 l 1771 3895 l 1772 3904 l + 1772 3913 l 1770 3921 l 1767 3929 l 1762 3936 l 1756 3944 l + 1747 3952 l 1736 3959 l 1724 3966 l 1711 3973 l 1696 3980 l + 1687 3984 l 1677 3988 l 1666 3992 l 1654 3996 l 1641 4000 l + 1628 4004 l 1613 4008 l 1598 4011 l 1582 4014 l 1566 4016 l + 1551 4017 l 1535 4018 l 1519 4018 l 1503 4018 l 1487 4017 l + 1470 4015 l 1453 4012 l 1435 4008 l 1416 4004 l 1398 4000 l + 1380 3995 l 1362 3989 l 1346 3984 l 1331 3978 l 1318 3972 l + 1306 3967 l 1297 3962 l 1289 3957 l 1284 3953 l 1280 3950 l + 1277 3946 l 1274 3943 l 1272 3940 l 1271 3936 l 1270 3933 l + 1270 3930 l 1270 3927 l 1271 3923 l 1273 3920 l 1274 3917 l + 1277 3914 l 1279 3911 l 1282 3909 l 1285 3906 l 1288 3904 l + 1291 3901 l 1294 3899 l 1297 3897 l 1305 3892 l 1313 3886 l + 1321 3881 l 1329 3875 l 1336 3869 l 1343 3863 l 1348 3857 l + 1352 3852 l 1354 3848 l 1355 3843 l 1356 3839 l 1356 3834 l + 1356 3829 l 1354 3824 l 1351 3819 l 1348 3814 l 1343 3809 l + 1338 3805 l 1331 3801 l 1323 3797 l 1314 3794 l 1304 3790 l + 1292 3786 l 1278 3782 l 1263 3777 l 1247 3772 l 1229 3767 l + 1212 3761 l 1194 3755 l 1176 3748 l 1159 3740 l 1141 3732 l + 1126 3724 l 1111 3716 l 1095 3706 l 1079 3696 l 1062 3686 l + 1046 3675 l 1029 3664 l 1014 3654 l 998 3644 l 984 3635 l + 972 3627 l 960 3620 l 950 3614 l 941 3610 l 936 3608 l + 932 3607 l 928 3606 l 924 3605 l 921 3605 l 917 3605 l + 914 3605 l 912 3606 l 909 3607 l 907 3608 l 905 3610 l + 903 3612 l 902 3615 l 901 3618 l 900 3621 l 900 3624 l + 899 3628 l 899 3632 l 900 3636 l 900 3641 l 901 3645 l + 902 3650 l 903 3655 l 905 3660 l 906 3665 l 908 3671 l + 912 3681 l 916 3692 l 921 3705 l 928 3718 l 935 3733 l + 943 3748 l 951 3764 l 961 3781 l 970 3797 l 980 3814 l + 991 3830 l 1001 3846 l 1012 3862 l 1022 3878 l 1032 3891 l + 1042 3905 l 1053 3919 l 1064 3934 l 1076 3948 l 1089 3963 l + 1101 3978 l 1115 3993 l 1128 4008 l 1141 4022 l 1154 4035 l + 1167 4047 l 1180 4059 l 1192 4069 l 1204 4079 l 1216 4088 l + 1229 4098 l 1242 4107 l 1256 4115 l 1271 4123 l 1285 4131 l + 1301 4138 l 1316 4144 l 1331 4150 l 1347 4155 l 1362 4159 l + 1376 4163 l 1391 4167 l 1405 4170 l 1419 4173 l 1432 4175 l + 1447 4177 l 1462 4180 l 1477 4182 l 1493 4184 l 1510 4185 l + 1526 4186 l 1542 4187 l 1558 4188 l 1574 4188 l 1589 4188 l + 1603 4187 l 1616 4186 l 1629 4185 l 1643 4183 l 1658 4180 l + 1672 4177 l 1687 4173 l 1702 4168 l 1716 4163 l 1730 4158 l + 1744 4152 l 1757 4146 l 1769 4141 l 1781 4135 l 1792 4130 l + 1805 4124 l 1818 4117 l 1831 4110 l 1845 4103 l 1858 4096 l + 1871 4089 l 1882 4082 l 1893 4076 l 1902 4071 l 1909 4066 l + 1916 4062 l 1923 4057 l 1929 4053 l 1935 4050 l 1941 4047 l + 1947 4046 l 1952 4045 l 1958 4045 l 1964 4046 l 1971 4049 l + 1978 4052 l 1987 4057 l 1996 4064 l 2007 4071 l 2019 4080 l + 2031 4089 l 2043 4099 l 2055 4109 l 2067 4120 l 2079 4130 l + 2089 4139 l 2100 4148 l 2111 4158 l 2122 4168 l 2134 4178 l + 2146 4189 l 2158 4199 l 2170 4210 l 2181 4220 l 2192 4229 l + 2202 4238 l 2212 4246 l 2222 4254 l 2232 4262 l 2242 4271 l + 2254 4280 l 2267 4290 l 2281 4300 l 2296 4312 l 2309 4322 l + 2321 4331 l 2328 4336 l 2331 4339 l + 2332 4339 l gs col31 1.00 shd ef gr gs col0 s gr +% Polyline +n 2876 5202 m 2877 5203 l 2880 5207 l 2887 5217 l 2897 5231 l 2908 5246 l + 2919 5259 l 2928 5271 l 2936 5281 l 2943 5289 l 2949 5296 l + 2957 5304 l 2965 5312 l 2974 5320 l 2983 5327 l 2993 5334 l + 3002 5341 l 3011 5347 l 3020 5352 l 3029 5358 l 3039 5364 l + 3050 5370 l 3062 5377 l 3073 5383 l 3084 5389 l 3094 5393 l + 3104 5398 l 3113 5401 l 3122 5405 l 3132 5408 l 3141 5411 l + 3151 5413 l 3159 5415 l 3168 5417 l 3175 5419 l 3183 5421 l + 3191 5423 l 3199 5424 l 3208 5426 l 3217 5428 l 3226 5430 l + 3234 5431 l 3242 5432 l 3250 5433 l 3259 5434 l 3268 5435 l + 3277 5436 l 3286 5436 l 3294 5436 l 3302 5437 l 3309 5437 l + 3317 5437 l 3325 5436 l 3335 5436 l 3345 5435 l 3351 5434 l + + 3352 5434 l gs col0 s gr +% Polyline +n 3161 5427 m 3162 5427 l 3166 5430 l 3176 5436 l 3192 5446 l 3211 5457 l + 3231 5469 l 3249 5480 l 3266 5489 l 3280 5497 l 3293 5504 l + 3303 5509 l 3314 5514 l 3325 5519 l 3336 5524 l 3347 5528 l + 3359 5532 l 3370 5535 l 3381 5538 l 3392 5540 l 3402 5543 l + 3412 5544 l 3422 5546 l 3432 5548 l 3442 5550 l 3454 5551 l + 3466 5553 l 3478 5554 l 3491 5556 l 3503 5556 l 3514 5557 l + 3525 5557 l 3536 5557 l 3546 5556 l 3556 5555 l 3566 5553 l + 3577 5551 l 3588 5549 l 3599 5546 l 3610 5543 l 3620 5540 l + 3630 5537 l 3640 5534 l 3650 5531 l 3661 5528 l 3672 5525 l + 3683 5521 l 3695 5518 l 3707 5514 l 3719 5511 l 3731 5507 l + 3741 5504 l 3752 5501 l 3762 5497 l 3773 5494 l 3784 5490 l + 3796 5487 l 3808 5483 l 3820 5479 l 3833 5476 l 3845 5473 l + 3856 5470 l 3868 5468 l 3879 5465 l 3892 5463 l 3905 5461 l + 3919 5459 l 3934 5457 l 3949 5455 l 3963 5453 l 3977 5452 l + 3990 5450 l 4002 5449 l 4015 5448 l 4027 5446 l 4041 5444 l + 4055 5442 l 4069 5440 l 4083 5438 l 4097 5435 l 4111 5431 l + 4125 5428 l 4138 5424 l 4149 5420 l 4160 5416 l 4173 5412 l + 4186 5407 l 4199 5401 l 4213 5396 l 4226 5390 l 4239 5384 l + 4252 5378 l 4265 5373 l 4276 5367 l 4288 5362 l 4301 5356 l + 4314 5350 l 4328 5344 l 4342 5338 l 4356 5332 l 4370 5326 l + 4383 5320 l 4395 5315 l 4407 5310 l 4418 5305 l 4429 5300 l + 4441 5296 l 4452 5291 l 4464 5286 l 4476 5280 l 4487 5275 l + 4498 5270 l 4508 5265 l 4517 5260 l 4525 5256 l 4535 5249 l + 4545 5242 l 4554 5235 l 4564 5227 l 4573 5218 l 4582 5209 l + 4590 5200 l 4597 5191 l 4603 5183 l 4609 5174 l 4616 5164 l + 4624 5152 l 4633 5137 l 4643 5122 l 4651 5108 l 4658 5098 l + 4661 5094 l + 4661 5093 l gs col0 s gr +% Polyline +n 2640 4897 m 2643 4902 l 2647 4907 l 2652 4912 l 2656 4917 l 2661 4921 l + 2666 4925 l 2672 4928 l 2678 4931 l 2685 4934 l 2692 4936 l + 2699 4938 l 2706 4939 l 2713 4940 l 2721 4941 l 2729 4942 l + 2736 4943 l 2743 4944 l 2750 4944 l 2756 4945 l 2763 4946 l + 2770 4947 l 2776 4947 l 2781 4948 l 2786 4947 l 2792 4947 l + 2798 4946 l 2805 4945 l 2813 4943 l 2821 4942 l 2828 4940 l + 2836 4939 l 2844 4937 l 2854 4935 l 2864 4933 l 2873 4930 l + 2881 4928 l 2889 4925 l 2899 4921 l 2908 4916 l 2918 4911 l + 2926 4905 l 2934 4899 l 2940 4894 l 2946 4889 l 2952 4883 l + 2958 4876 l 2964 4870 l 2969 4863 l 2974 4856 l 2980 4849 l + 2986 4841 l 2992 4832 l 2999 4822 l 3005 4813 l 3012 4805 l + 3018 4796 l 3024 4787 l 3031 4778 l 3038 4770 l 3044 4762 l + 3050 4756 l 3055 4751 l 3059 4745 l 3064 4740 l 3068 4736 l + 3071 4731 l 3074 4727 l 3076 4722 l 3077 4715 l 3077 4708 l + 3077 4701 l 3076 4695 l 3075 4689 l 3073 4682 l 3071 4674 l + 3069 4667 l 3066 4661 l 3064 4656 l 3062 4650 l 3059 4644 l + 3056 4639 l 3054 4633 l 3051 4628 l 3048 4623 l 3044 4617 l + 3041 4611 l 3037 4605 l 3033 4599 l 3029 4593 l 3028 4591 l + 3026 4589 l 3024 4587 l 3022 4585 l 3020 4583 l 3017 4582 l + 3013 4581 l 3008 4581 l 3003 4582 l 2997 4584 l 2991 4586 l + 2983 4589 l 2975 4593 l 2966 4598 l 2956 4605 l 2945 4612 l + 2934 4619 l 2923 4627 l 2910 4637 l 2896 4647 l 2881 4658 l + 2866 4670 l 2850 4683 l 2833 4697 l 2816 4710 l 2800 4724 l + 2783 4738 l 2767 4751 l 2752 4764 l 2738 4776 l 2725 4788 l + 2713 4799 l 2702 4809 l 2692 4818 l 2679 4830 l 2668 4841 l + 2659 4851 l 2651 4860 l 2646 4868 l 2641 4875 l 2639 4880 l + 2637 4885 l 2637 4889 l 2637 4892 l 2638 4895 l + cp gs col20 1.00 shd ef gr gs col0 s gr +% Polyline +n 2891 5190 m 2893 5191 l 2902 5194 l 2915 5198 l 2928 5203 l 2938 5206 l + 2947 5209 l 2955 5212 l 2964 5215 l 2974 5218 l 2983 5221 l + 2992 5224 l 3001 5226 l 3009 5228 l 3018 5230 l 3028 5231 l + 3037 5232 l 3046 5234 l 3054 5235 l 3062 5235 l 3070 5236 l + 3078 5237 l 3086 5237 l 3094 5238 l 3101 5238 l 3108 5239 l + 3115 5239 l 3123 5239 l 3131 5239 l 3139 5239 l 3145 5239 l + 3153 5239 l 3161 5239 l 3169 5239 l 3176 5239 l 3180 5238 l + 3182 5238 l 3183 5238 l 3184 5238 l 3185 5237 l 3186 5237 l + 3186 5236 l 3187 5236 l + 3187 5235 l gs col0 s gr +% Polyline +n 2468 6609 m 2462 6602 l 2456 6595 l 2448 6588 l 2440 6581 l 2432 6573 l + 2423 6566 l 2415 6559 l 2408 6553 l 2400 6547 l 2391 6540 l + 2382 6534 l 2373 6527 l 2363 6521 l 2353 6515 l 2344 6510 l + 2335 6506 l 2325 6501 l 2314 6497 l 2303 6494 l 2290 6490 l + 2278 6487 l 2265 6484 l 2253 6482 l 2242 6480 l 2232 6479 l + 2222 6478 l 2212 6476 l 2201 6476 l 2190 6475 l 2178 6474 l + 2167 6474 l 2155 6474 l 2144 6473 l 2134 6474 l 2122 6474 l + 2111 6474 l 2098 6475 l 2085 6475 l 2071 6476 l 2058 6477 l + 2044 6479 l 2031 6480 l 2018 6482 l 2006 6484 l 1996 6485 l + 1985 6487 l 1974 6489 l 1963 6491 l 1951 6493 l 1938 6496 l + 1926 6499 l 1913 6502 l 1900 6505 l 1887 6508 l 1875 6511 l + 1862 6515 l 1851 6517 l 1839 6521 l 1826 6524 l 1813 6527 l + 1799 6531 l 1785 6535 l 1770 6540 l 1755 6544 l 1740 6549 l + 1726 6553 l 1711 6558 l 1697 6563 l 1684 6567 l 1671 6572 l + 1656 6578 l 1640 6584 l 1624 6590 l 1608 6596 l 1592 6603 l + 1575 6611 l 1560 6618 l 1545 6625 l 1531 6631 l 1519 6637 l + 1508 6643 l 1498 6649 l 1484 6657 l 1472 6665 l 1461 6673 l + 1450 6682 l 1442 6690 l 1435 6697 l 1429 6704 l 1424 6710 l + 1418 6718 l 1413 6727 l 1409 6737 l 1406 6747 l 1404 6757 l + 1403 6767 l 1403 6775 l 1403 6783 l 1404 6793 l 1406 6803 l + 1408 6813 l 1410 6824 l 1412 6833 l 1415 6843 l 1418 6852 l + 1421 6861 l 1425 6871 l 1430 6881 l 1435 6891 l 1441 6901 l + 1446 6910 l 1453 6918 l 1459 6925 l 1467 6933 l 1476 6941 l + 1486 6949 l 1496 6956 l 1507 6963 l 1518 6969 l 1529 6975 l + 1538 6979 l 1548 6984 l 1558 6988 l 1570 6992 l 1582 6996 l + 1594 7000 l 1606 7004 l 1618 7007 l 1630 7010 l 1642 7013 l + 1654 7015 l 1667 7017 l 1680 7019 l 1695 7021 l 1710 7022 l + 1726 7024 l 1741 7025 l 1756 7026 l 1770 7027 l 1785 7028 l + 1796 7028 l 1809 7029 l 1822 7029 l 1835 7030 l 1849 7030 l + 1863 7030 l 1877 7031 l 1891 7031 l 1904 7031 l 1916 7032 l + 1928 7032 l 1939 7033 l 1952 7033 l 1965 7033 l 1979 7034 l + 1992 7034 l 2006 7035 l 2020 7035 l 2032 7036 l 2044 7036 l + 2056 7037 l 2067 7037 l 2077 7037 l 2088 7037 l 2099 7038 l + 2111 7038 l 2123 7038 l 2136 7038 l 2148 7038 l 2160 7038 l + 2172 7038 l 2183 7038 l 2191 7038 l 2200 7038 l 2209 7037 l + 2219 7036 l 2229 7035 l 2240 7033 l 2251 7029 l 2262 7025 l + 2273 7020 l 2284 7013 l 2295 7006 l 2306 6997 l 2317 6987 l + 2328 6976 l 2337 6964 l 2347 6951 l 2357 6937 l 2367 6922 l + 2377 6905 l 2388 6887 l 2398 6868 l 2408 6849 l 2418 6830 l + 2428 6811 l 2437 6793 l 2445 6775 l 2452 6759 l 2458 6743 l + 2464 6729 l 2469 6717 l 2474 6701 l 2478 6687 l 2481 6674 l + 2483 6663 l 2483 6653 l 2483 6643 l 2482 6635 l 2480 6628 l + 2478 6622 l 2475 6617 l 2472 6613 l + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +n 4102 4658 m 4100 4659 l 4092 4665 l 4080 4673 l 4068 4681 l 4059 4686 l + 4051 4690 l 4044 4693 l 4036 4696 l 4027 4698 l 4018 4700 l + 4009 4701 l 4001 4702 l 3994 4703 l 3986 4703 l 3978 4704 l + 3969 4704 l 3960 4705 l 3952 4705 l 3944 4705 l 3936 4706 l + 3927 4706 l 3917 4706 l 3907 4706 l 3897 4705 l 3888 4704 l + 3880 4703 l 3871 4701 l 3861 4699 l 3850 4696 l 3839 4693 l + 3829 4690 l 3819 4686 l 3811 4683 l 3802 4680 l 3793 4676 l + 3783 4672 l 3773 4668 l 3764 4663 l 3755 4658 l 3746 4654 l + 3737 4648 l 3728 4642 l 3719 4636 l 3709 4629 l 3699 4622 l + 3690 4615 l 3682 4609 l 3674 4603 l 3667 4597 l 3659 4591 l + 3651 4585 l 3643 4579 l 3635 4573 l 3627 4567 l 3619 4562 l + 3611 4557 l 3603 4552 l 3594 4547 l 3585 4541 l 3575 4536 l + 3564 4530 l 3554 4525 l 3544 4521 l 3535 4516 l 3525 4512 l + 3515 4507 l 3504 4503 l 3492 4499 l 3480 4494 l 3468 4490 l + 3456 4487 l 3445 4484 l 3435 4481 l 3425 4479 l 3414 4477 l + 3403 4475 l 3391 4473 l 3379 4471 l 3367 4469 l 3356 4468 l + 3345 4466 l 3335 4465 l 3325 4464 l 3314 4464 l 3303 4463 l + 3292 4462 l 3281 4462 l 3270 4462 l 3259 4462 l 3248 4462 l + 3238 4463 l 3229 4463 l 3217 4465 l 3204 4466 l 3192 4468 l + 3179 4471 l 3167 4474 l 3156 4476 l 3146 4479 l 3137 4482 l + 3129 4485 l 3122 4489 l 3114 4493 l 3106 4497 l 3099 4502 l + 3091 4506 l 3083 4511 l 3075 4517 l 3068 4521 l 3060 4526 l + 3050 4532 l 3039 4539 l 3025 4547 l 3010 4556 l 2996 4565 l + 2986 4571 l 2982 4574 l + 2981 4574 l gs col0 s gr +% Polyline +n 2940 2986 m 2939 2985 l 2932 2981 l 2920 2973 l 2905 2963 l 2891 2954 l + 2879 2947 l 2869 2941 l 2859 2937 l 2849 2933 l 2839 2930 l + 2827 2927 l 2816 2924 l 2804 2922 l 2792 2920 l 2781 2919 l + 2770 2918 l 2760 2918 l 2748 2917 l 2736 2918 l 2724 2918 l + 2712 2919 l 2700 2921 l 2689 2923 l 2679 2925 l 2669 2928 l + 2659 2932 l 2648 2936 l 2637 2941 l 2627 2946 l 2617 2952 l + 2608 2957 l 2601 2963 l 2593 2969 l 2586 2976 l 2579 2983 l + 2572 2991 l 2566 2999 l 2560 3008 l 2556 3016 l 2552 3024 l + 2548 3033 l 2545 3042 l 2542 3053 l 2540 3063 l 2538 3074 l + 2536 3085 l 2535 3095 l 2534 3105 l 2534 3114 l 2534 3124 l + 2534 3135 l 2534 3145 l 2536 3156 l 2537 3166 l 2540 3175 l + 2542 3184 l 2546 3193 l 2550 3202 l 2555 3212 l 2560 3222 l + 2567 3231 l 2573 3240 l 2579 3248 l 2586 3255 l 2592 3262 l + 2599 3268 l 2607 3275 l 2616 3281 l 2624 3288 l 2632 3293 l + 2640 3298 l 2648 3303 l 2656 3307 l 2664 3311 l 2673 3315 l + 2683 3319 l 2693 3323 l 2702 3326 l 2712 3329 l 2721 3331 l + 2730 3333 l 2740 3335 l 2750 3336 l 2762 3338 l 2773 3339 l + 2783 3340 l 2794 3340 l 2803 3341 l 2812 3341 l 2822 3341 l + 2832 3342 l 2842 3342 l 2852 3341 l 2862 3341 l 2871 3341 l + 2880 3340 l 2889 3339 l 2898 3339 l 2907 3337 l 2917 3336 l + 2926 3335 l 2935 3334 l 2944 3332 l 2951 3331 l 2961 3329 l + 2970 3328 l 2980 3326 l 2989 3324 l 2997 3323 l 3005 3323 l + 3012 3322 l 3019 3322 l 3026 3323 l 3033 3324 l 3040 3326 l + 3047 3329 l 3053 3332 l 3061 3336 l 3070 3340 l 3079 3344 l + 3088 3348 l 3097 3350 l 3107 3352 l 3117 3353 l 3129 3352 l + 3140 3352 l 3150 3351 l 3159 3349 l 3167 3348 l 3175 3346 l + 3182 3343 l 3188 3340 l 3193 3336 l 3197 3331 l 3200 3325 l + 3203 3317 l 3205 3308 l 3206 3298 l 3206 3287 l 3206 3278 l + 3205 3268 l 3204 3257 l 3201 3246 l 3198 3235 l 3195 3225 l + 3191 3217 l 3187 3210 l 3181 3203 l 3173 3195 l 3164 3187 l + 3158 3182 l + 3157 3181 l gs col0 s gr +% Polyline +n 3309 2031 m 3318 2017 l 3328 2004 l 3338 1992 l 3349 1979 l 3360 1967 l + 3371 1955 l 3382 1943 l 3394 1932 l 3405 1922 l 3417 1913 l + 3428 1904 l 3440 1895 l 3452 1886 l 3466 1878 l 3480 1869 l + 3495 1861 l 3511 1853 l 3528 1845 l 3544 1839 l 3561 1834 l + 3577 1830 l 3592 1828 l 3607 1828 l 3621 1829 l 3632 1831 l + 3644 1835 l 3656 1839 l 3668 1845 l 3679 1853 l 3691 1861 l + 3702 1871 l 3713 1882 l 3723 1893 l 3733 1904 l 3741 1916 l + 3749 1928 l 3756 1940 l 3762 1952 l 3767 1965 l 3772 1978 l + 3777 1991 l 3781 2006 l 3785 2021 l 3788 2037 l 3791 2054 l + 3793 2071 l 3795 2088 l 3797 2106 l 3798 2123 l 3798 2140 l + 3799 2157 l 3799 2174 l 3799 2189 l 3799 2205 l 3798 2222 l + 3798 2239 l 3797 2258 l 3796 2277 l 3795 2296 l 3793 2316 l + 3792 2336 l 3790 2356 l 3787 2376 l 3785 2395 l 3783 2414 l + 3780 2433 l 3777 2451 l 3774 2469 l 3770 2486 l 3767 2504 l + 3763 2522 l 3758 2541 l 3753 2560 l 3748 2580 l 3743 2599 l + 3737 2619 l 3731 2638 l 3724 2657 l 3718 2676 l 3711 2693 l + 3705 2710 l 3698 2726 l 3692 2741 l 3685 2756 l 3677 2773 l + 3669 2789 l 3661 2805 l 3651 2821 l 3641 2837 l 3631 2853 l + 3620 2869 l 3609 2884 l 3597 2899 l 3586 2912 l 3574 2925 l + 3562 2936 l 3551 2947 l 3539 2957 l 3527 2967 l 3514 2976 l + 3500 2985 l 3486 2993 l 3471 3001 l 3455 3009 l 3439 3016 l + 3422 3022 l 3405 3027 l 3389 3031 l 3373 3034 l 3358 3036 l + 3343 3037 l 3328 3038 l 3313 3037 l 3298 3036 l 3283 3033 l + 3267 3030 l 3251 3025 l 3235 3019 l 3219 3013 l 3204 3005 l + 3189 2997 l 3175 2988 l 3162 2979 l 3150 2969 l 3139 2958 l + 3129 2948 l 3120 2936 l 3111 2924 l 3103 2911 l 3095 2896 l + 3087 2881 l 3080 2865 l 3074 2849 l 3068 2832 l 3063 2816 l + 3059 2799 l 3055 2784 l 3052 2768 l 3049 2754 l 3047 2740 l + 3045 2726 l 3044 2712 l 3043 2697 l 3042 2683 l 3042 2667 l + 3042 2652 l 3043 2636 l 3044 2620 l 3046 2604 l 3048 2588 l + 3051 2572 l 3055 2557 l 3058 2542 l 3062 2526 l 3066 2512 l + 3071 2498 l 3076 2483 l 3081 2467 l 3088 2451 l 3094 2433 l + 3101 2416 l 3109 2398 l 3116 2379 l 3124 2361 l 3132 2344 l + 3140 2326 l 3148 2309 l 3156 2293 l 3164 2277 l 3172 2262 l + 3180 2247 l 3188 2231 l 3196 2216 l 3204 2200 l 3213 2184 l + 3222 2168 l 3232 2152 l 3241 2136 l 3250 2120 l 3260 2105 l + 3269 2091 l 3277 2077 l 3286 2065 l 3294 2053 l 3301 2041 l + + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +45.000 slw +n 2498 3459 m 2499 3459 l 2505 3459 l 2517 3459 l 2532 3460 l 2545 3461 l + 2555 3461 l 2563 3462 l 2571 3464 l 2579 3467 l 2587 3471 l + 2595 3476 l 2603 3481 l 2610 3488 l 2617 3495 l 2623 3501 l + 2629 3507 l 2636 3514 l 2643 3522 l 2651 3530 l 2658 3538 l + 2665 3546 l 2672 3553 l 2679 3560 l 2686 3568 l 2693 3576 l + 2701 3584 l 2708 3592 l 2716 3599 l 2723 3606 l 2730 3613 l + 2737 3620 l 2744 3627 l 2752 3634 l 2761 3642 l 2769 3649 l + 2777 3657 l 2785 3664 l 2792 3672 l 2799 3679 l 2807 3687 l + 2815 3695 l 2824 3704 l 2833 3713 l 2841 3722 l 2850 3730 l + 2859 3737 l 2866 3743 l 2874 3749 l 2883 3756 l 2892 3762 l + 2902 3769 l 2911 3775 l 2921 3781 l 2931 3787 l 2940 3793 l + 2950 3798 l 2959 3803 l 2969 3809 l 2979 3814 l 2990 3820 l + 3001 3826 l 3012 3831 l 3024 3836 l 3035 3841 l 3045 3845 l + 3056 3849 l 3066 3853 l 3077 3856 l 3089 3859 l 3101 3862 l + 3114 3865 l 3127 3868 l 3141 3870 l 3154 3872 l 3166 3874 l + 3179 3876 l 3189 3877 l 3201 3878 l 3212 3879 l 3225 3879 l + 3238 3880 l 3251 3880 l 3264 3881 l 3277 3881 l 3289 3881 l + 3301 3881 l 3312 3880 l 3323 3880 l 3336 3879 l 3349 3878 l + 3362 3876 l 3376 3875 l 3390 3872 l 3404 3870 l 3417 3867 l + 3430 3864 l 3442 3860 l 3454 3857 l 3466 3852 l 3478 3848 l + 3491 3843 l 3504 3837 l 3518 3831 l 3531 3825 l 3544 3818 l + 3556 3813 l 3568 3807 l 3579 3802 l 3590 3796 l 3601 3791 l + 3612 3785 l 3624 3780 l 3636 3774 l 3647 3768 l 3659 3762 l + 3670 3756 l 3681 3750 l 3692 3744 l 3703 3738 l 3715 3731 l + 3727 3724 l 3739 3717 l 3751 3709 l 3764 3701 l 3775 3693 l + 3785 3686 l 3795 3680 l 3803 3673 l 3812 3666 l 3821 3658 l + 3829 3650 l 3837 3643 l 3844 3637 l 3852 3631 l 3859 3626 l + 3866 3622 l 3873 3619 l 3881 3617 l 3891 3614 l 3901 3613 l + 3910 3612 l 3920 3611 l 3928 3610 l 3936 3610 l 3945 3610 l + 3954 3609 l 3964 3609 l 3975 3609 l 3982 3609 l + 3983 3609 l gs col0 s gr +% Polyline +30.000 slw +n 2870 2736 m 2876 2727 l 2882 2719 l 2888 2710 l 2895 2701 l 2901 2690 l + 2907 2679 l 2913 2667 l 2919 2654 l 2925 2640 l 2931 2625 l + 2935 2612 l 2940 2599 l 2945 2585 l 2950 2569 l 2956 2552 l + 2962 2534 l 2967 2515 l 2973 2496 l 2979 2477 l 2985 2459 l + 2991 2440 l 2996 2423 l 3001 2406 l 3006 2390 l 3011 2374 l + 3016 2359 l 3021 2343 l 3026 2327 l 3031 2311 l 3036 2295 l + 3041 2279 l 3046 2264 l 3051 2249 l 3056 2235 l 3061 2222 l + 3065 2210 l 3069 2199 l 3073 2188 l 3078 2175 l 3083 2163 l + 3088 2151 l 3092 2139 l 3097 2127 l 3102 2114 l 3107 2102 l + 3112 2091 l 3117 2080 l 3121 2070 l 3125 2060 l 3129 2051 l + 3133 2039 l 3138 2028 l 3142 2016 l 3147 2003 l 3152 1991 l + 3156 1979 l 3160 1968 l 3164 1957 l 3167 1948 l 3170 1939 l + 3173 1929 l 3176 1919 l 3179 1909 l 3180 1899 l 3181 1889 l + 3180 1879 l 3179 1869 l 3176 1859 l 3173 1851 l 3170 1844 l + 3166 1836 l 3161 1827 l 3155 1819 l 3149 1811 l 3141 1803 l + 3133 1796 l 3125 1790 l 3116 1785 l 3107 1782 l 3098 1780 l + 3088 1778 l 3077 1778 l 3066 1780 l 3053 1782 l 3040 1785 l + 3027 1789 l 3014 1794 l 3001 1800 l 2989 1805 l 2978 1811 l + 2967 1816 l 2958 1822 l 2947 1829 l 2936 1836 l 2926 1843 l + 2916 1851 l 2906 1860 l 2896 1870 l 2886 1880 l 2876 1891 l + 2866 1902 l 2856 1915 l 2848 1924 l 2840 1934 l 2831 1946 l + 2822 1958 l 2812 1971 l 2801 1986 l 2790 2000 l 2780 2016 l + 2769 2031 l 2758 2047 l 2748 2062 l 2738 2077 l 2729 2092 l + 2720 2107 l 2711 2122 l 2702 2137 l 2693 2153 l 2684 2169 l + 2675 2185 l 2666 2202 l 2658 2219 l 2650 2235 l 2642 2251 l + 2635 2265 l 2628 2279 l 2622 2292 l 2616 2304 l 2611 2315 l + 2605 2327 l 2600 2339 l 2595 2350 l 2591 2361 l 2586 2373 l + 2582 2385 l 2578 2396 l 2575 2408 l 2572 2421 l 2569 2433 l + 2566 2446 l 2564 2460 l 2562 2472 l 2560 2486 l 2558 2500 l + 2557 2516 l 2555 2533 l 2554 2551 l 2553 2568 l 2552 2586 l + 2551 2604 l 2551 2621 l 2552 2637 l 2552 2652 l 2553 2666 l + 2555 2680 l 2558 2697 l 2562 2713 l 2567 2728 l 2573 2742 l + 2579 2756 l 2586 2768 l 2593 2779 l 2600 2788 l 2607 2796 l + 2614 2803 l 2622 2810 l 2630 2817 l 2639 2824 l 2648 2829 l + 2658 2834 l 2667 2838 l 2677 2841 l 2686 2843 l 2696 2845 l + 2708 2845 l 2720 2845 l 2733 2844 l 2747 2841 l 2760 2838 l + 2772 2832 l 2783 2826 l 2792 2820 l 2802 2813 l 2811 2804 l + 2821 2795 l 2830 2785 l 2839 2774 l 2848 2764 l 2856 2754 l + 2863 2744 l + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +n 3489 1649 m 3490 1649 l 3494 1646 l 3504 1640 l 3520 1632 l 3539 1622 l + 3559 1611 l 3578 1601 l 3596 1593 l 3612 1586 l 3626 1581 l + 3639 1577 l 3652 1573 l 3665 1571 l 3678 1569 l 3692 1568 l + 3706 1568 l 3721 1568 l 3736 1569 l 3751 1571 l 3766 1573 l + 3780 1576 l 3793 1580 l 3805 1584 l 3817 1588 l 3829 1593 l + 3840 1599 l 3852 1605 l 3863 1612 l 3875 1621 l 3886 1630 l + 3897 1640 l 3907 1650 l 3917 1661 l 3925 1672 l 3933 1684 l + 3940 1696 l 3946 1707 l 3952 1719 l 3957 1733 l 3962 1748 l + 3968 1765 l 3974 1785 l 3980 1807 l 3986 1830 l 3992 1852 l + 3998 1873 l 4002 1888 l 4004 1897 l 4005 1901 l + 4005 1902 l gs col0 s gr +% Polyline +n 3278 1680 m 3278 1679 l 3277 1674 l 3274 1664 l 3270 1650 l 3265 1634 l + 3260 1620 l 3256 1607 l 3251 1598 l 3246 1589 l 3241 1583 l + 3234 1576 l 3227 1571 l 3219 1566 l 3209 1561 l 3199 1557 l + 3188 1553 l 3177 1550 l 3165 1548 l 3154 1546 l 3143 1545 l + 3132 1544 l 3120 1543 l 3107 1543 l 3093 1544 l 3079 1545 l + 3064 1547 l 3050 1550 l 3037 1554 l 3024 1558 l 3011 1563 l + 3001 1569 l 2991 1575 l 2980 1582 l 2969 1590 l 2957 1599 l + 2945 1609 l 2933 1620 l 2920 1631 l 2908 1643 l 2896 1654 l + 2885 1666 l 2873 1678 l 2864 1688 l 2854 1697 l 2844 1708 l + 2834 1719 l 2823 1730 l 2812 1742 l 2801 1755 l 2789 1768 l + 2778 1782 l 2766 1795 l 2755 1809 l 2744 1823 l 2734 1836 l + 2724 1849 l 2714 1862 l 2705 1876 l 2696 1889 l 2687 1903 l + 2678 1917 l 2669 1932 l 2660 1948 l 2651 1964 l 2642 1980 l + 2633 1997 l 2624 2014 l 2616 2030 l 2608 2046 l 2601 2062 l + 2594 2077 l 2588 2092 l 2582 2106 l 2576 2119 l 2570 2134 l + 2564 2150 l 2558 2165 l 2553 2181 l 2547 2197 l 2541 2213 l + 2536 2229 l 2531 2244 l 2526 2260 l 2521 2274 l 2517 2288 l + 2512 2301 l 2508 2313 l 2504 2325 l 2499 2338 l 2495 2352 l + 2489 2366 l 2484 2380 l 2479 2394 l 2473 2409 l 2467 2423 l + 2462 2437 l 2456 2451 l 2451 2464 l 2446 2477 l 2441 2490 l + 2437 2503 l 2432 2517 l 2426 2532 l 2420 2549 l 2413 2568 l + 2406 2590 l 2398 2613 l 2391 2635 l 2385 2652 l 2381 2664 l + 2379 2669 l + 2379 2670 l gs col0 s gr +% Polyline +n 4036 5613 m 4048 5621 l 4060 5629 l 4071 5637 l 4083 5644 l 4095 5652 l + 4106 5659 l 4117 5666 l 4128 5673 l 4138 5679 l 4147 5685 l + 4157 5691 l 4165 5696 l 4176 5703 l 4187 5710 l 4198 5717 l + 4210 5724 l 4221 5732 l 4233 5739 l 4245 5747 l 4255 5754 l + 4265 5760 l 4275 5767 l 4284 5773 l 4294 5779 l 4304 5785 l + 4314 5792 l 4323 5798 l 4333 5805 l 4342 5810 l 4350 5816 l + 4357 5820 l 4363 5824 l 4373 5831 l 4382 5836 l 4391 5841 l + 4399 5845 l 4406 5848 l 4412 5850 l 4419 5851 l 4426 5851 l + 4433 5851 l 4440 5850 l 4446 5848 l 4451 5846 l 4457 5844 l + 4462 5840 l 4467 5837 l 4471 5834 l 4475 5830 l 4479 5826 l + 4482 5821 l 4486 5816 l 4490 5811 l 4493 5806 l 4497 5801 l + 4501 5796 l 4506 5790 l 4509 5785 l 4512 5780 l 4516 5774 l + 4519 5767 l 4521 5760 l 4523 5753 l 4524 5747 l 4524 5740 l + 4524 5734 l 4523 5727 l 4522 5719 l 4521 5713 l 4520 5707 l + 4518 5702 l 4515 5697 l 4512 5691 l 4508 5686 l 4504 5682 l + 4499 5677 l 4494 5673 l 4489 5668 l 4482 5663 l 4475 5658 l + 4468 5653 l 4461 5648 l 4454 5643 l 4446 5638 l 4437 5632 l + 4427 5626 l 4417 5620 l 4408 5614 l 4400 5609 l 4391 5604 l + 4382 5598 l 4371 5591 l 4361 5584 l 4351 5578 l 4341 5571 l + 4332 5565 l 4322 5559 l 4313 5553 l 4303 5546 l 4292 5540 l + 4283 5534 l 4274 5528 l 4266 5523 l 4258 5519 l 4252 5515 l + 4245 5511 l 4238 5507 l 4231 5503 l 4224 5499 l 4217 5495 l + 4210 5491 l 4203 5486 l 4195 5480 l 4186 5474 l 4177 5468 l + 4167 5460 l 4158 5453 l 4149 5447 l 4142 5442 l 4136 5437 l + 4131 5434 l 4127 5431 l 4124 5429 l 4120 5428 l 4116 5428 l + 4112 5428 l 4106 5428 l 4100 5429 l 4093 5430 l 4085 5431 l + 4076 5433 l 4066 5434 l 4054 5436 l 4042 5438 l 4029 5440 l + 4017 5441 l 4005 5443 l 3993 5445 l 3981 5447 l 3969 5449 l + 3957 5450 l 3944 5452 l 3932 5455 l 3920 5457 l 3910 5459 l + 3900 5460 l 3892 5462 l 3885 5464 l 3882 5465 l 3880 5465 l + 3878 5466 l 3876 5467 l 3874 5468 l 3872 5468 l 3871 5469 l + 3869 5470 l 3868 5471 l 3867 5472 l 3867 5474 l 3866 5475 l + 3866 5476 l 3866 5478 l 3866 5479 l 3867 5481 l 3868 5483 l + 3869 5485 l 3870 5487 l 3872 5489 l 3874 5491 l 3876 5493 l + 3878 5496 l 3881 5498 l 3884 5501 l 3887 5504 l 3894 5510 l + 3904 5517 l 3914 5526 l 3926 5535 l 3939 5545 l 3954 5555 l + 3968 5566 l 3983 5576 l 3997 5586 l 4011 5596 l 4024 5605 l + + cp gs col31 1.00 shd ef gr gs col0 s gr +7.500 slw +% Rotated Ellipse +gs +3291 2663 tr +-345.998 rot +n 0 0 179 279 0 360 DrawEllipse 345.998 rot +gs 0.00 setgray ef gr gs col0 s gr +gr + +% Polyline +30.000 slw +n 2303 4762 m 2309 4770 l 2316 4777 l 2323 4784 l 2330 4792 l 2337 4799 l + 2344 4805 l 2350 4811 l 2356 4816 l 2364 4823 l 2372 4830 l + 2381 4837 l 2390 4843 l 2399 4848 l 2408 4852 l 2415 4854 l + 2423 4857 l 2432 4859 l 2441 4861 l 2451 4863 l 2461 4864 l + 2471 4866 l 2480 4867 l 2489 4867 l 2500 4868 l 2510 4869 l + 2522 4869 l 2533 4869 l 2543 4869 l 2554 4869 l 2563 4868 l + 2572 4867 l 2582 4866 l 2592 4865 l 2602 4863 l 2613 4861 l + 2623 4859 l 2633 4857 l 2642 4855 l 2651 4853 l 2661 4850 l + 2672 4848 l 2682 4845 l 2693 4842 l 2703 4839 l 2712 4836 l + 2720 4833 l 2728 4831 l 2736 4827 l 2744 4824 l 2751 4820 l + 2759 4816 l 2766 4812 l 2773 4807 l 2779 4802 l 2785 4797 l + 2792 4791 l 2799 4784 l 2807 4777 l 2815 4769 l 2823 4760 l + 2830 4752 l 2838 4744 l 2844 4737 l 2851 4730 l 2858 4723 l + 2865 4715 l 2873 4706 l 2880 4698 l 2888 4690 l 2895 4682 l + 2901 4674 l 2908 4667 l 2915 4658 l 2923 4649 l 2931 4640 l + 2939 4630 l 2947 4621 l 2953 4612 l 2960 4604 l 2965 4597 l + 2970 4589 l 2975 4582 l 2979 4574 l 2984 4566 l 2987 4558 l + 2990 4551 l 2993 4544 l 2994 4537 l 2996 4530 l 2996 4522 l + 2997 4514 l 2997 4506 l 2997 4497 l 2996 4488 l 2996 4480 l + 2995 4472 l 2994 4464 l 2993 4455 l 2991 4446 l 2989 4437 l + 2987 4427 l 2984 4418 l 2981 4410 l 2977 4403 l 2972 4395 l + 2967 4388 l 2961 4381 l 2954 4373 l 2947 4367 l 2939 4360 l + 2932 4354 l 2926 4349 l 2919 4344 l 2912 4340 l 2904 4335 l + 2896 4330 l 2888 4326 l 2881 4322 l 2873 4318 l 2866 4315 l + 2859 4311 l 2851 4308 l 2843 4305 l 2834 4302 l 2825 4300 l + 2817 4297 l 2809 4295 l 2801 4294 l 2793 4293 l 2785 4292 l + 2776 4291 l 2767 4291 l 2758 4291 l 2750 4291 l 2742 4292 l + 2734 4293 l 2724 4294 l 2714 4296 l 2704 4298 l 2693 4302 l + 2684 4305 l 2676 4309 l 2672 4312 l 2667 4315 l 2661 4320 l + 2654 4326 l 2645 4333 l 2635 4342 l 2623 4353 l 2609 4366 l + 2593 4380 l 2575 4397 l 2564 4407 l 2552 4418 l 2538 4430 l + 2524 4443 l 2509 4457 l 2493 4472 l 2477 4487 l 2460 4503 l + 2443 4519 l 2426 4535 l 2410 4552 l 2394 4567 l 2380 4582 l + 2366 4597 l 2353 4610 l 2342 4623 l 2331 4635 l 2322 4646 l + 2314 4658 l 2306 4668 l 2300 4679 l 2295 4688 l 2291 4698 l + 2288 4706 l 2287 4714 l 2286 4722 l 2286 4729 l 2287 4735 l + 2289 4741 l 2291 4746 l 2294 4750 l 2297 4755 l 2300 4759 l + + cp gs col20 1.00 shd ef gr gs col0 s gr +7.500 slw +% Rotated Ellipse +gs +2748 2543 tr +-345.998 rot +n 0 0 130 238 0 360 DrawEllipse 345.998 rot +gs 0.00 setgray ef gr gs col0 s gr +gr + +% Rotated Ellipse +gs +2738 2495 tr +-350.003 rot +n 0 0 55 105 0 360 DrawEllipse 350.003 rot +gs col7 1.00 shd ef gr gs col0 s gr +gr + +% Polyline +30.000 slw +n 2288 6848 m 2292 6837 l 2298 6827 l 2305 6815 l 2313 6804 l 2322 6793 l + 2332 6783 l 2342 6773 l 2351 6764 l 2360 6757 l 2369 6750 l + 2378 6743 l 2386 6738 l 2395 6732 l 2403 6726 l 2413 6721 l + 2422 6716 l 2430 6711 l 2439 6707 l 2448 6703 l 2456 6699 l + 2465 6694 l 2474 6689 l 2484 6684 l 2495 6679 l 2506 6674 l + 2518 6668 l 2529 6663 l 2540 6658 l 2550 6653 l 2560 6649 l + 2570 6645 l 2580 6641 l 2591 6637 l 2602 6633 l 2614 6629 l + 2626 6626 l 2637 6622 l 2648 6619 l 2659 6616 l 2670 6614 l + 2681 6611 l 2692 6608 l 2705 6606 l 2718 6603 l 2731 6601 l + 2744 6598 l 2757 6596 l 2770 6594 l 2782 6592 l 2794 6591 l + 2805 6589 l 2817 6588 l 2829 6586 l 2842 6585 l 2855 6584 l + 2868 6583 l 2880 6583 l 2892 6582 l 2903 6582 l 2914 6582 l + 2925 6581 l 2936 6582 l 2948 6582 l 2960 6582 l 2972 6583 l + 2985 6584 l 2997 6585 l 3008 6586 l 3020 6587 l 3031 6589 l + 3041 6590 l 3053 6592 l 3065 6594 l 3077 6597 l 3090 6599 l + 3102 6602 l 3114 6605 l 3126 6607 l 3136 6610 l 3146 6613 l + 3158 6617 l 3170 6620 l 3182 6625 l 3195 6629 l 3207 6634 l + 3218 6639 l 3228 6644 l 3238 6650 l 3248 6655 l 3258 6661 l + 3268 6668 l 3279 6676 l 3290 6684 l 3300 6692 l 3309 6700 l + 3318 6709 l 3325 6715 l 3332 6722 l 3339 6730 l 3346 6738 l + 3353 6746 l 3360 6755 l 3367 6763 l 3373 6772 l 3378 6780 l + 3383 6788 l 3389 6797 l 3394 6808 l 3399 6820 l 3404 6832 l + 3409 6844 l 3413 6856 l 3416 6868 l 3420 6879 l 3422 6888 l + 3424 6898 l 3426 6908 l 3428 6919 l 3430 6930 l 3432 6940 l + 3433 6951 l 3435 6960 l 3436 6970 l 3437 6978 l 3437 6983 l + 3437 6988 l 3437 6993 l 3436 6998 l 3435 7004 l 3433 7009 l + 3431 7014 l 3427 7020 l 3422 7025 l 3417 7030 l 3410 7036 l + 3402 7041 l 3393 7046 l 3382 7050 l 3371 7055 l 3358 7060 l + 3346 7064 l 3333 7068 l 3319 7072 l 3303 7076 l 3287 7080 l + 3268 7084 l 3248 7088 l 3227 7091 l 3205 7095 l 3182 7098 l + 3157 7101 l 3133 7104 l 3107 7106 l 3081 7108 l 3056 7109 l + 3030 7109 l 3004 7110 l 2978 7109 l 2952 7108 l 2926 7107 l + 2902 7105 l 2877 7102 l 2852 7099 l 2826 7096 l 2800 7092 l + 2773 7088 l 2746 7083 l 2718 7077 l 2690 7071 l 2662 7065 l + 2634 7059 l 2607 7052 l 2581 7045 l 2556 7038 l 2531 7031 l + 2508 7024 l 2486 7017 l 2466 7010 l 2447 7003 l 2429 6996 l + 2413 6990 l 2398 6983 l 2381 6976 l 2366 6968 l 2352 6960 l + 2339 6952 l 2328 6944 l 2318 6936 l 2309 6928 l 2302 6920 l + 2296 6912 l 2291 6904 l 2288 6896 l 2285 6888 l 2284 6881 l + 2283 6874 l 2283 6867 l 2284 6861 l 2286 6854 l + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +n 2232 4239 m 2224 4242 l 2216 4247 l 2207 4251 l 2198 4256 l 2190 4261 l + 2183 4267 l 2176 4272 l 2169 4278 l 2162 4286 l 2154 4294 l + 2147 4303 l 2140 4313 l 2135 4320 l 2130 4329 l 2125 4338 l + 2119 4349 l 2114 4359 l 2110 4369 l 2106 4379 l 2104 4387 l + 2101 4396 l 2099 4405 l 2098 4414 l 2097 4423 l 2096 4432 l + 2096 4441 l 2096 4449 l 2095 4458 l 2095 4466 l 2095 4475 l + 2095 4484 l 2095 4495 l 2095 4505 l 2096 4514 l 2096 4523 l + 2098 4532 l 2099 4540 l 2102 4548 l 2105 4557 l 2109 4566 l + 2114 4575 l 2119 4583 l 2125 4591 l 2131 4599 l 2138 4606 l + 2147 4614 l 2156 4622 l 2166 4630 l 2176 4638 l 2186 4645 l + 2196 4651 l 2204 4656 l 2213 4661 l 2222 4665 l 2231 4668 l + 2240 4671 l 2250 4674 l 2260 4676 l 2269 4677 l 2279 4679 l + 2289 4680 l 2300 4681 l 2312 4683 l 2325 4684 l 2338 4685 l + 2351 4686 l 2362 4686 l 2373 4687 l 2384 4688 l 2395 4688 l + 2407 4688 l 2418 4688 l 2430 4688 l 2442 4686 l 2452 4685 l + 2463 4683 l 2472 4680 l 2481 4677 l 2490 4674 l 2500 4670 l + 2510 4665 l 2521 4660 l 2530 4655 l 2540 4650 l 2548 4644 l + 2557 4639 l 2567 4632 l 2577 4624 l 2587 4616 l 2597 4607 l + 2606 4598 l 2614 4589 l 2620 4581 l 2626 4573 l 2631 4565 l + 2635 4558 l 2639 4550 l 2642 4541 l 2645 4533 l 2647 4526 l + 2648 4519 l 2650 4512 l 2651 4504 l 2653 4494 l 2654 4484 l + 2654 4473 l 2654 4462 l 2653 4451 l 2651 4442 l 2649 4432 l + 2647 4421 l 2644 4410 l 2641 4398 l 2637 4387 l 2633 4377 l + 2630 4368 l 2626 4359 l 2621 4351 l 2616 4342 l 2610 4334 l + 2604 4326 l 2597 4319 l 2591 4312 l 2584 4306 l 2577 4301 l + 2571 4296 l 2563 4291 l 2554 4286 l 2544 4281 l 2533 4276 l + 2521 4271 l 2509 4266 l 2496 4262 l 2483 4257 l 2471 4254 l + 2458 4250 l 2444 4247 l 2429 4244 l 2413 4240 l 2397 4237 l + 2381 4234 l 2365 4232 l 2351 4230 l 2337 4228 l 2325 4227 l + 2314 4226 l 2299 4225 l 2286 4225 l 2274 4226 l 2263 4228 l + 2253 4230 l 2245 4233 l 2238 4236 l + cp gs col20 1.00 shd ef gr gs col0 s gr +7.500 slw +% Rotated Ellipse +gs +3260 2603 tr +-350.003 rot +n 0 0 55 105 0 360 DrawEllipse 350.003 rot +gs col7 1.00 shd ef gr gs col0 s gr +gr + +% Polyline +30.000 slw +n 2246 4048 m 2247 4040 l 2248 4030 l 2251 4020 l 2254 4009 l 2259 3999 l + 2263 3989 l 2268 3983 l 2272 3976 l 2278 3969 l 2284 3963 l + 2291 3957 l 2298 3951 l 2304 3946 l 2311 3941 l 2317 3937 l + 2324 3932 l 2331 3928 l 2339 3924 l 2346 3920 l 2354 3916 l + 2362 3913 l 2369 3911 l 2377 3908 l 2385 3906 l 2394 3903 l + 2404 3901 l 2413 3899 l 2423 3898 l 2431 3896 l 2440 3896 l + 2448 3895 l 2456 3894 l 2465 3894 l 2474 3893 l 2483 3893 l + 2492 3893 l 2499 3893 l 2507 3892 l 2517 3892 l 2527 3892 l + 2538 3891 l 2548 3891 l 2558 3891 l 2567 3891 l 2576 3891 l + 2585 3892 l 2594 3893 l 2604 3895 l 2612 3897 l 2620 3899 l + 2628 3901 l 2637 3905 l 2646 3909 l 2655 3913 l 2665 3919 l + 2674 3925 l 2681 3929 l 2688 3935 l 2697 3941 l 2705 3948 l + 2713 3955 l 2721 3962 l 2727 3969 l 2733 3975 l 2738 3981 l + 2743 3988 l 2747 3996 l 2751 4003 l 2754 4011 l 2757 4019 l + 2759 4026 l 2761 4033 l 2763 4040 l 2765 4048 l 2767 4057 l + 2768 4066 l 2770 4076 l 2771 4085 l 2772 4095 l 2772 4105 l + 2773 4115 l 2773 4125 l 2772 4137 l 2771 4149 l 2770 4161 l + 2768 4173 l 2765 4184 l 2762 4193 l 2758 4202 l 2754 4211 l + 2748 4220 l 2741 4228 l 2733 4236 l 2725 4243 l 2717 4250 l + 2708 4255 l 2701 4259 l 2693 4263 l 2684 4267 l 2674 4270 l + 2664 4274 l 2654 4277 l 2643 4280 l 2633 4282 l 2622 4284 l + 2612 4286 l 2602 4287 l 2591 4288 l 2579 4289 l 2566 4290 l + 2553 4291 l 2540 4292 l 2527 4292 l 2515 4292 l 2503 4292 l + 2492 4292 l 2481 4291 l 2470 4291 l 2458 4290 l 2447 4289 l + 2435 4287 l 2423 4285 l 2412 4283 l 2402 4281 l 2392 4278 l + 2383 4275 l 2373 4270 l 2362 4265 l 2351 4259 l 2341 4251 l + 2331 4243 l 2322 4235 l 2314 4227 l 2306 4219 l 2299 4211 l + 2292 4202 l 2286 4192 l 2279 4182 l 2273 4172 l 2268 4162 l + 2264 4153 l 2261 4145 l 2257 4135 l 2254 4125 l 2252 4115 l + 2251 4106 l 2250 4098 l 2249 4091 l 2248 4085 l 2247 4078 l + 2246 4071 l 2246 4063 l 2246 4056 l + cp gs col20 1.00 shd ef gr gs col0 s gr +% Polyline +n 1481 6669 m 1482 6670 l 1487 6673 l 1499 6680 l 1516 6690 l 1534 6700 l + 1551 6710 l 1567 6719 l 1580 6726 l 1593 6732 l 1605 6737 l + 1615 6741 l 1626 6745 l 1637 6749 l 1649 6752 l 1661 6756 l + 1674 6759 l 1687 6762 l 1700 6765 l 1713 6767 l 1725 6770 l + 1737 6771 l 1749 6773 l 1762 6775 l 1774 6776 l 1788 6778 l + 1802 6779 l 1817 6780 l 1833 6781 l 1848 6782 l 1864 6783 l + 1879 6783 l 1894 6784 l 1908 6784 l 1922 6784 l 1934 6784 l + 1946 6784 l 1959 6784 l 1973 6784 l 1987 6784 l 2002 6783 l + 2017 6783 l 2032 6783 l 2047 6782 l 2062 6782 l 2077 6781 l + 2092 6780 l 2107 6780 l 2121 6779 l 2138 6779 l 2156 6778 l + 2175 6777 l 2194 6776 l 2213 6776 l 2232 6775 l 2250 6774 l + 2267 6773 l 2282 6773 l 2295 6772 l 2306 6772 l 2315 6771 l + 2317 6771 l 2319 6771 l 2321 6771 l 2323 6771 l 2325 6771 l + 2326 6771 l 2328 6771 l 2329 6771 l 2330 6771 l 2331 6771 l + 2332 6770 l 2333 6770 l 2334 6770 l 2335 6770 l 2334 6771 l + 2333 6771 l 2332 6771 l 2331 6771 l 2330 6771 l 2329 6771 l + 2328 6771 l + 2327 6771 l gs col0 s gr +% Polyline +n 3533 6267 m 3533 6268 l 3534 6275 l 3535 6289 l 3536 6305 l 3537 6320 l + 3538 6331 l 3538 6341 l 3538 6349 l 3536 6359 l 3535 6368 l + 3532 6377 l 3529 6385 l 3525 6392 l 3522 6398 l 3517 6404 l + 3512 6410 l 3506 6417 l 3500 6423 l 3493 6428 l 3486 6433 l + 3480 6436 l 3474 6440 l 3466 6443 l 3458 6447 l 3448 6450 l + 3439 6453 l 3429 6456 l 3419 6459 l 3410 6461 l 3400 6463 l + 3390 6466 l 3377 6469 l 3364 6472 l 3350 6476 l 3335 6480 l + 3319 6485 l 3304 6489 l 3287 6495 l 3275 6499 l 3261 6504 l + 3246 6509 l 3229 6516 l 3210 6523 l 3188 6531 l 3164 6541 l + 3139 6551 l 3114 6560 l 3091 6569 l 3075 6576 l 3064 6580 l + 3060 6582 l + 3059 6582 l gs col0 s gr +% Polyline +n 3983 6181 m 3983 6182 l 3983 6186 l 3984 6196 l 3986 6211 l 3987 6230 l + 3989 6250 l 3991 6268 l 3992 6284 l 3993 6299 l 3994 6311 l + 3995 6322 l 3996 6333 l 3997 6345 l 3997 6357 l 3998 6369 l + 3998 6380 l 3998 6392 l 3998 6403 l 3998 6413 l 3997 6423 l + 3997 6431 l 3996 6439 l 3994 6448 l 3991 6457 l 3988 6465 l + 3984 6474 l 3979 6481 l 3974 6488 l 3968 6494 l 3962 6499 l + 3955 6503 l 3947 6507 l 3937 6511 l 3927 6516 l 3915 6520 l + 3903 6523 l 3892 6527 l 3880 6531 l 3869 6533 l 3859 6537 l + 3847 6540 l 3834 6544 l 3821 6547 l 3807 6551 l 3793 6555 l + 3779 6558 l 3766 6561 l 3753 6564 l 3742 6566 l 3730 6569 l + 3718 6571 l 3704 6573 l 3690 6576 l 3675 6579 l 3660 6583 l + 3645 6586 l 3629 6590 l 3614 6595 l 3598 6599 l 3582 6604 l + 3570 6609 l 3557 6613 l 3543 6618 l 3528 6624 l 3511 6631 l + 3493 6639 l 3472 6648 l 3449 6658 l 3426 6668 l 3403 6679 l + 3381 6688 l 3363 6696 l 3350 6702 l 3343 6705 l + 3339 6707 l gs col0 s gr +% Polyline +n 2263 6883 m 2260 6890 l 2258 6899 l 2256 6908 l 2254 6916 l 2254 6925 l + 2253 6933 l 2253 6942 l 2252 6951 l 2252 6962 l 2252 6972 l + 2253 6982 l 2253 6991 l 2254 7000 l 2254 7009 l 2256 7018 l + 2257 7027 l 2259 7036 l 2262 7044 l 2264 7049 l 2267 7055 l + 2271 7062 l 2277 7069 l 2284 7076 l 2292 7084 l 2301 7091 l + 2312 7099 l 2320 7104 l 2330 7109 l 2340 7115 l 2352 7122 l + 2364 7128 l 2378 7135 l 2392 7142 l 2406 7148 l 2420 7155 l + 2433 7160 l 2446 7166 l 2459 7171 l 2472 7175 l 2485 7179 l + 2498 7184 l 2512 7188 l 2527 7192 l 2542 7195 l 2558 7199 l + 2574 7202 l 2590 7205 l 2606 7208 l 2623 7210 l 2639 7212 l + 2654 7214 l 2669 7215 l 2686 7217 l 2703 7219 l 2721 7220 l + 2741 7222 l 2760 7223 l 2780 7225 l 2799 7226 l 2818 7227 l + 2837 7229 l 2854 7230 l 2871 7231 l 2887 7232 l 2903 7232 l + 2919 7233 l 2935 7234 l 2951 7235 l 2968 7236 l 2985 7237 l + 3002 7237 l 3020 7238 l 3037 7239 l 3054 7240 l 3071 7240 l + 3088 7241 l 3104 7242 l 3121 7243 l 3135 7243 l 3151 7244 l + 3166 7244 l 3183 7245 l 3201 7246 l 3219 7246 l 3237 7247 l + 3256 7247 l 3274 7248 l 3293 7248 l 3311 7249 l 3328 7249 l + 3345 7249 l 3361 7249 l 3377 7249 l 3392 7249 l 3408 7249 l + 3425 7248 l 3442 7248 l 3459 7247 l 3476 7246 l 3494 7245 l + 3512 7244 l 3530 7242 l 3548 7241 l 3566 7239 l 3583 7238 l + 3600 7236 l 3617 7234 l 3634 7232 l 3649 7230 l 3664 7228 l + 3680 7226 l 3697 7224 l 3715 7222 l 3733 7220 l 3752 7217 l + 3771 7215 l 3789 7212 l 3807 7209 l 3825 7207 l 3842 7204 l + 3859 7202 l 3874 7199 l 3889 7197 l 3903 7195 l 3918 7192 l + 3933 7189 l 3948 7186 l 3963 7183 l 3978 7180 l 3993 7177 l + 4007 7174 l 4021 7171 l 4035 7167 l 4049 7164 l 4061 7160 l + 4074 7157 l 4085 7153 l 4097 7150 l 4109 7146 l 4121 7143 l + 4133 7138 l 4146 7134 l 4160 7129 l 4174 7124 l 4188 7119 l + 4203 7114 l 4217 7108 l 4232 7103 l 4246 7097 l 4260 7092 l + 4273 7086 l 4287 7081 l 4300 7075 l 4314 7070 l 4329 7063 l + 4344 7057 l 4359 7050 l 4375 7044 l 4391 7037 l 4407 7030 l + 4423 7023 l 4437 7017 l 4452 7010 l 4465 7004 l 4478 6999 l + 4490 6994 l 4503 6988 l 4516 6982 l 4529 6976 l 4542 6970 l + 4555 6964 l 4567 6959 l 4578 6954 l 4589 6949 l 4598 6944 l + 4607 6940 l 4615 6937 l 4622 6934 l 4634 6928 l 4644 6922 l + 4654 6917 l 4662 6912 l 4668 6907 l 4673 6902 l 4677 6897 l + 4682 6890 l 4686 6883 l 4689 6876 l 4692 6869 l 4694 6862 l + 4695 6856 l 4696 6849 l 4696 6842 l 4697 6835 l 4696 6828 l + 4696 6822 l 4695 6816 l 4695 6809 l 4694 6802 l 4693 6795 l + 4693 6788 l 4692 6782 l 4692 6775 l 4691 6768 l 4691 6760 l + 4690 6751 l 4690 6743 l 4689 6734 l 4688 6729 l 4688 6723 l + 4686 6717 l 4684 6712 l 4682 6706 l 4679 6701 l 4675 6698 l + 4671 6695 l 4666 6693 l 4660 6693 l 4653 6693 l 4645 6695 l + 4635 6699 l 4624 6703 l 4612 6709 l 4598 6715 l 4584 6722 l + 4570 6730 l 4556 6737 l 4542 6745 l 4529 6751 l 4516 6758 l + 4502 6765 l 4487 6772 l 4471 6779 l 4455 6787 l 4439 6794 l + 4424 6802 l 4408 6808 l 4394 6815 l 4380 6821 l 4368 6826 l + 4355 6831 l 4342 6836 l 4329 6841 l 4316 6846 l 4303 6851 l + 4289 6856 l 4276 6860 l 4262 6864 l 4250 6869 l 4237 6873 l + 4225 6876 l 4213 6880 l 4202 6883 l 4191 6886 l 4179 6890 l + 4167 6893 l 4154 6897 l 4140 6901 l 4126 6905 l 4111 6908 l + 4096 6912 l 4081 6916 l 4067 6919 l 4052 6923 l 4038 6926 l + 4023 6930 l 4008 6933 l 3992 6936 l 3976 6939 l 3959 6943 l + 3941 6946 l 3922 6950 l 3903 6953 l 3884 6957 l 3865 6960 l + 3846 6963 l 3829 6965 l 3812 6968 l 3795 6970 l 3780 6973 l + 3764 6974 l 3748 6976 l 3732 6978 l 3716 6980 l 3700 6982 l + 3683 6983 l 3666 6985 l 3649 6986 l 3633 6987 l 3617 6988 l + 3601 6989 l 3587 6990 l 3572 6991 l 3558 6992 l 3544 6993 l + 3529 6994 l 3514 6994 l 3498 6995 l 3481 6996 l 3463 6997 l + 3445 6997 l 3426 6998 l 3407 6999 l 3388 7000 l 3369 7000 l + 3350 7001 l 3331 7001 l 3312 7002 l 3296 7002 l 3280 7003 l + 3263 7003 l 3245 7004 l 3226 7004 l 3207 7005 l 3187 7005 l + 3167 7006 l 3146 7006 l 3125 7006 l 3104 7006 l 3084 7007 l + 3064 7007 l 3044 7007 l 3025 7007 l 3007 7007 l 2989 7007 l + 2972 7007 l 2953 7006 l 2934 7006 l 2915 7005 l 2895 7005 l + 2875 7004 l 2856 7003 l 2836 7002 l 2817 7001 l 2798 7000 l + 2780 6999 l 2763 6997 l 2746 6996 l 2731 6995 l 2717 6993 l + 2703 6992 l 2691 6991 l 2674 6988 l 2658 6986 l 2643 6984 l + 2628 6982 l 2613 6979 l 2598 6976 l 2584 6973 l 2571 6970 l + 2559 6967 l 2548 6965 l 2538 6962 l 2528 6959 l 2517 6956 l + 2505 6952 l 2493 6948 l 2482 6944 l 2470 6940 l 2459 6936 l + 2449 6932 l 2439 6928 l 2431 6924 l 2424 6920 l 2415 6915 l + 2406 6910 l 2398 6904 l 2390 6899 l 2382 6893 l 2375 6888 l + 2369 6883 l 2364 6878 l 2356 6872 l 2348 6866 l 2340 6860 l + 2332 6855 l 2325 6850 l 2320 6846 l 2316 6843 l 2312 6840 l + 2308 6838 l 2305 6836 l 2301 6835 l 2298 6835 l 2295 6836 l + 2292 6838 l 2287 6842 l 2282 6848 l 2276 6856 l 2271 6865 l + 2267 6874 l + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +n 3095 6246 m 3096 6246 l 3100 6246 l 3109 6246 l 3123 6247 l 3141 6248 l + 3159 6248 l 3177 6249 l 3193 6251 l 3207 6252 l 3220 6253 l + 3232 6255 l 3244 6257 l 3256 6260 l 3269 6263 l 3283 6266 l + 3299 6271 l 3317 6276 l 3337 6282 l 3358 6289 l 3378 6295 l + 3394 6301 l 3405 6304 l 3409 6306 l + 3410 6306 l gs col3 s gr +% Polyline +n 3599 6276 m 3600 6276 l 3605 6277 l 3616 6278 l 3633 6279 l 3654 6281 l + 3676 6283 l 3697 6285 l 3717 6287 l 3734 6289 l 3749 6291 l + 3763 6293 l 3777 6295 l 3791 6297 l 3805 6300 l 3821 6302 l + 3838 6306 l 3858 6309 l 3879 6314 l 3902 6318 l 3924 6323 l + 3942 6326 l 3953 6329 l 3958 6330 l + 3959 6330 l gs col3 s gr +% Polyline +15.000 slw +n 4281 6302 m 4288 6296 l 4297 6291 l 4305 6287 l 4314 6283 l 4322 6281 l + 4330 6280 l 4337 6279 l 4344 6279 l 4352 6280 l 4359 6282 l + 4366 6284 l 4373 6287 l 4380 6290 l 4387 6294 l 4394 6300 l + 4401 6306 l 4408 6312 l 4414 6319 l 4420 6326 l 4426 6334 l + 4432 6343 l 4437 6353 l 4441 6363 l 4444 6373 l 4445 6380 l + 4446 6388 l 4447 6397 l 4447 6407 l 4446 6417 l 4445 6426 l + 4444 6435 l 4443 6444 l 4441 6452 l 4439 6461 l 4436 6470 l + 4433 6479 l 4430 6489 l 4426 6497 l 4422 6505 l 4418 6513 l + 4413 6519 l 4408 6526 l 4401 6533 l 4395 6540 l 4387 6546 l + 4380 6551 l 4373 6554 l 4366 6558 l 4357 6560 l 4346 6562 l + 4336 6562 l 4325 6561 l 4315 6559 l 4306 6557 l 4297 6554 l + 4288 6550 l 4279 6545 l 4271 6541 l 4263 6536 l 4257 6531 l + 4250 6526 l 4245 6521 l 4239 6516 l 4234 6510 l 4230 6504 l + 4227 6499 l 4224 6492 l 4221 6486 l 4219 6478 l 4218 6470 l + 4217 6462 l 4217 6454 l 4216 6446 l 4217 6437 l 4217 6428 l + 4218 6418 l 4220 6409 l 4221 6402 l 4223 6394 l 4224 6386 l + 4227 6378 l 4230 6370 l 4234 6361 l 4238 6354 l 4242 6347 l + 4246 6341 l 4251 6333 l 4257 6326 l 4263 6319 l 4269 6312 l + 4275 6306 l + cp gs col7 1.00 shd ef gr gs col0 s gr +% Polyline +30.000 slw +n 3248 6546 m 3249 6546 l 3254 6546 l 3265 6547 l 3280 6548 l 3296 6550 l + 3312 6552 l 3326 6553 l 3338 6555 l 3349 6557 l 3359 6560 l + 3369 6562 l 3380 6566 l 3392 6570 l 3406 6576 l 3422 6582 l + 3438 6589 l 3453 6596 l 3464 6600 l 3469 6603 l + 3470 6603 l gs col3 s gr +% Polyline +n 3440 6504 m 3441 6504 l 3445 6504 l 3456 6504 l 3470 6504 l 3485 6504 l + 3500 6505 l 3513 6505 l 3525 6506 l 3535 6507 l 3545 6508 l + 3555 6510 l 3565 6512 l 3577 6515 l 3590 6518 l 3606 6523 l + 3622 6528 l 3637 6532 l 3647 6535 l 3652 6537 l + 3653 6537 l gs col3 s gr +% Polyline +n 3560 6402 m 3561 6402 l 3566 6403 l 3578 6404 l 3597 6405 l 3620 6407 l + 3644 6409 l 3666 6411 l 3686 6413 l 3704 6415 l 3720 6417 l + 3734 6419 l 3747 6421 l 3760 6423 l 3774 6425 l 3787 6428 l + 3803 6431 l 3819 6434 l 3838 6439 l 3857 6443 l 3875 6447 l + 3890 6451 l 3899 6453 l 3903 6454 l + 3904 6454 l gs col3 s gr +% Polyline +n 2861 6429 m 2863 6429 l 2866 6430 l 2872 6431 l 2881 6432 l 2887 6433 l + 2894 6434 l 2902 6435 l 2912 6437 l 2923 6439 l 2935 6442 l + 2947 6444 l 2959 6447 l 2971 6450 l 2983 6454 l 2993 6457 l + 3004 6460 l 3016 6464 l 3029 6469 l 3044 6474 l 3060 6480 l + 3078 6487 l 3095 6493 l 3109 6499 l 3117 6502 l 3121 6504 l + + 3122 6504 l gs col3 s gr +% Polyline +n 2594 6492 m 2595 6492 l 2600 6492 l 2611 6493 l 2628 6493 l 2649 6494 l + 2671 6495 l 2692 6497 l 2712 6498 l 2729 6499 l 2745 6501 l + 2759 6502 l 2774 6504 l 2786 6506 l 2799 6508 l 2813 6511 l + 2828 6514 l 2845 6517 l 2864 6521 l 2884 6526 l 2906 6531 l + 2927 6536 l 2945 6540 l 2959 6543 l 2968 6545 l 2971 6546 l + + 2972 6546 l gs col3 s gr +% Polyline +n 3023 6360 m 3024 6360 l 3028 6361 l 3037 6362 l 3052 6365 l 3070 6368 l + 3089 6371 l 3107 6374 l 3123 6377 l 3138 6380 l 3151 6383 l + 3163 6385 l 3175 6388 l 3187 6391 l 3200 6395 l 3213 6399 l + 3228 6403 l 3246 6409 l 3265 6415 l 3285 6421 l 3304 6428 l + 3320 6433 l 3330 6436 l 3334 6438 l + 3335 6438 l gs col3 s gr +$F2psEnd +rs diff --git a/share/examples/BSD_daemon/beastie.fig b/share/examples/BSD_daemon/beastie.fig new file mode 100644 index 000000000000..df03e83f4836 --- /dev/null +++ b/share/examples/BSD_daemon/beastie.fig @@ -0,0 +1,270 @@ +#FIG 3.2 +# SPDX-License-Identifier: Beerware +# +# ---------------------------------------------------------------------------- +# "THE BEER-WARE LICENSE" (Revision 42): +# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you +# can do whatever you want with this stuff. If we meet some day, and you think +# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +# ---------------------------------------------------------------------------- +# +# +Landscape +Center +Inches +A4 +100.00 +Single +-2 +1200 2 +1 1 0 1 0 0 47 0 20 0.000 1 6.0388 2748 2543 130 238 2748 2543 2878 2305 +1 1 0 1 0 7 46 0 20 0.000 1 6.1087 2738 2495 55 105 2738 2495 2793 2495 +1 1 0 1 0 0 47 0 20 0.000 1 6.0388 3291 2663 179 279 3291 2663 3470 2384 +1 1 0 1 0 7 46 0 20 0.000 1 6.1087 3260 2603 55 105 3260 2603 3315 2603 +3 0 0 3 0 7 49 0 -1 0.000 0 0 0 16 + 4102 4658 4050 4695 4005 4703 3933 4706 3881 4706 3821 4688 + 3746 4658 3671 4601 3615 4556 3536 4515 3450 4481 3333 4463 + 3228 4459 3127 4481 3086 4511 2981 4574 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 1 0 3 0 20 50 0 20 0.000 0 0 0 18 + 2628 4864 2636 4898 2666 4928 2696 4939 2745 4943 2782 4950 + 2812 4943 2895 4928 2943 4894 2973 4860 3011 4804 3052 4751 + 3078 4729 3078 4695 3067 4661 3052 4628 3030 4594 3003 4553 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 +3 1 0 3 0 20 47 0 20 0.000 0 0 0 21 + 2250 4691 2302 4766 2358 4819 2403 4856 2478 4868 2565 4871 + 2640 4856 2726 4834 2778 4808 2835 4748 2910 4665 2970 4594 + 3000 4538 2996 4474 2985 4399 2925 4346 2868 4313 2801 4290 + 2733 4290 2673 4305 2632 4346 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 +3 1 0 3 0 20 46 0 20 0.000 0 0 0 19 + 2287 4215 2231 4238 2182 4264 2141 4305 2096 4391 2096 4455 + 2092 4534 2122 4598 2208 4665 2272 4680 2377 4688 2460 4691 + 2561 4643 2636 4571 2651 4511 2658 4459 2632 4361 2591 4305 + 2505 4256 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 +3 1 0 3 0 20 45 0 20 0.000 0 0 0 20 + 2250 4088 2242 4054 2257 3986 2310 3938 2366 3908 2441 3893 + 2508 3893 2568 3889 2621 3896 2670 3919 2741 3975 2763 4031 + 2775 4099 2771 4200 2715 4260 2617 4290 2490 4294 2377 4283 + 2302 4223 2253 4140 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 +3 0 0 3 0 7 49 0 -1 0.000 0 0 0 22 + 2940 2986 2861 2930 2771 2915 2677 2919 2595 2960 2546 3020 + 2531 3106 2535 3185 2583 3260 2647 3305 2718 3335 2805 3342 + 2880 3342 2955 3331 3007 3320 3045 3324 3093 3357 3165 3350 + 3202 3339 3210 3279 3195 3211 3157 3181 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 0.000 +3 0 0 3 0 7 50 0 -1 0.000 0 0 0 8 + 2891 5190 2947 5209 3000 5228 3056 5235 3101 5239 3146 5239 + 3187 5239 3187 5235 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 0 0 3 0 7 50 0 -1 0.000 0 0 0 8 + 2876 5202 2951 5306 3015 5351 3108 5404 3176 5419 3240 5434 + 3315 5438 3352 5434 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 0 0 3 0 7 50 0 -1 0.000 0 0 0 14 + 3161 5427 3326 5528 3416 5546 3540 5565 3637 5535 3753 5501 + 3862 5464 4005 5449 4132 5434 4293 5359 4421 5303 4533 5258 + 4597 5198 4661 5093 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 0.000 +3 1 0 3 0 31 48 0 20 0.000 0 0 0 22 + 3851 5483 4050 5625 4166 5696 4278 5768 4372 5831 4413 5854 + 4447 5850 4473 5835 4488 5813 4515 5779 4526 5749 4522 5704 + 4503 5678 4462 5648 4413 5618 4331 5565 4252 5513 4211 5494 + 4121 5426 4121 5426 3993 5445 3866 5464 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 +3 1 0 3 0 13 51 0 20 0.000 0 0 0 55 + 2291 6462 2420 6447 2549 6444 2672 6444 2774 6441 2849 6387 + 2951 6357 3026 6321 3068 6294 3059 6210 3026 6153 2996 6063 + 2981 5991 3017 5991 3077 6030 3113 6075 3179 6057 3251 6060 + 3308 6063 3347 6096 3392 6150 3455 6132 3500 6135 3521 6186 + 3536 6255 3539 6309 3563 6237 3593 6159 3629 6090 3692 6060 + 3764 6054 3827 6069 3893 6111 3956 6159 3980 6204 3983 6156 + 4022 6138 4109 6138 4199 6132 4283 6102 4346 6081 4421 6042 + 4466 6144 4523 6264 4583 6402 4625 6546 4667 6663 4682 6717 + 4520 6837 4004 7044 3467 7131 2816 7128 2456 7047 2246 6816 + 2006 6510 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 +3 1 0 3 0 7 49 0 20 0.000 0 0 0 13 + 3168 2255 3315 2009 3424 1894 3629 1784 3784 1943 3806 2158 + 3786 2470 3693 2773 3553 2975 3328 3070 3103 2971 3034 2731 + 3043 2543 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 +3 0 0 3 0 7 45 0 -1 0.000 0 0 0 7 + 1481 6669 1601 6744 1744 6777 1919 6787 2111 6780 2363 6769 + 2327 6771 + 0.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 1 0 3 0 7 44 0 20 0.000 0 0 0 36 + 2294 6825 2258 6885 2252 6930 2252 6993 2258 7044 2288 7092 + 2462 7179 2618 7215 2900 7233 3104 7242 3407 7254 3617 7236 + 3926 7194 4094 7155 4280 7086 4505 6987 4637 6927 4676 6906 + 4697 6861 4697 6822 4691 6783 4691 6738 4679 6669 4553 6741 + 4358 6834 4220 6879 4037 6930 3770 6978 3560 6993 3338 7002 + 2957 7011 2666 6993 2522 6960 2414 6921 2363 6876 2315 6843 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 +3 1 0 3 0 7 49 0 20 0.000 0 0 0 21 + 2504 6663 2474 6609 2408 6552 2339 6501 2243 6477 2138 6471 + 2006 6480 1874 6510 1669 6567 1475 6654 1418 6711 1397 6762 + 1412 6843 1445 6921 1523 6978 1637 7017 1781 7029 1946 7032 + 2069 7038 2177 7038 2321 7038 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3599 6276 3776 6291 3959 6330 + 0.000 1.000 0.000 +3 1 0 2 0 7 43 0 20 0.000 0 0 0 14 + 4232 6357 4280 6294 4331 6276 4373 6282 4415 6315 4451 6369 + 4445 6444 4424 6516 4367 6567 4304 6561 4253 6531 4223 6501 + 4214 6456 4220 6399 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 +3 0 0 3 0 7 45 0 -1 0.000 0 0 0 7 + 3533 6267 3542 6357 3524 6399 3491 6435 3428 6459 3309 6482 + 3059 6582 + 0.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3440 6504 3544 6502 3653 6537 + 0.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3248 6546 3359 6552 3470 6603 + 0.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3560 6402 3755 6417 3904 6454 + 0.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 4 + 2861 6429 2861 6429 2979 6447 3122 6504 + 0.000 1.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 2594 6492 2769 6497 2972 6546 + 0.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3023 6360 3173 6383 3335 6438 + 0.000 1.000 0.000 +3 0 0 3 0 7 45 0 -1 0.000 0 0 0 8 + 3983 6181 3998 6342 4001 6447 3971 6504 3887 6528 3758 6567 + 3599 6588 3339 6707 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000 +3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3 + 3095 6246 3240 6248 3410 6306 + 0.000 1.000 0.000 +3 1 0 3 0 7 46 0 20 0.000 0 0 0 17 + 2291 6976 2265 6844 2375 6738 2450 6702 2561 6645 2666 6612 + 2795 6588 2915 6579 3029 6585 3152 6612 3239 6645 3320 6705 + 3389 6786 3422 6876 3440 6984 3437 7056 2957 7152 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 +3 0 0 4 0 7 49 0 -1 0.000 0 0 0 18 + 2498 3459 2578 3459 2613 3489 2673 3554 2728 3614 2793 3669 + 2853 3739 2948 3799 3053 3854 3173 3879 3328 3884 3453 3864 + 3583 3799 3688 3749 3818 3669 3858 3614 3943 3609 3983 3609 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 0.000 +3 1 0 3 0 7 49 0 20 0.000 0 0 0 17 + 2786 2845 2877 2727 2925 2661 3009 2376 3075 2175 3131 2050 + 3174 1929 3192 1869 3114 1746 2940 1824 2871 1890 2712 2103 + 2598 2340 2562 2427 2538 2709 2616 2814 2679 2850 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 +3 1 0 3 0 20 52 0 20 0.000 0 0 0 142 + 2136 3087 2170 2963 2229 2861 2391 2682 2418 2498 2498 2228 + 2476 2126 2452 2000 2401 1725 2407 1577 2476 1395 2483 1365 + 2719 1094 2978 878 3235 725 3394 659 3490 731 3394 806 + 3277 932 3166 1080 3112 1163 3103 1253 3112 1364 3151 1425 + 3235 1418 3397 1334 3616 1277 3871 1265 4150 1298 4628 1478 + 4793 1646 4861 1725 5006 1706 5273 1568 5288 1490 5281 1223 + 5141 998 5101 908 5189 866 5326 893 5465 1010 5708 1328 + 5789 1577 5836 1830 5765 2093 5513 2438 5207 2654 5056 2760 + 5078 2729 5072 3058 4988 3368 4829 3607 4565 3850 4502 3970 + 4486 4088 4511 4213 4589 4330 4643 4455 4679 4633 4688 4958 + 4667 5107 4607 5230 4613 5344 4733 5685 4928 5985 5221 6195 + 5570 6348 5993 6443 6480 6542 6773 6623 6966 6698 7141 6825 + 7206 6977 7208 7110 7062 7250 6923 7320 6513 7397 6481 7403 + 6518 7493 6468 7502 6120 7505 5571 7526 5298 7547 5241 7532 + 5298 7487 5958 7130 6174 6998 6249 6935 6291 6995 6342 7076 + 6368 7155 6408 7205 6608 7170 6756 7115 6878 7035 6873 6959 + 6750 6851 6543 6779 5985 6713 5568 6632 5271 6554 5003 6462 + 4821 6389 4673 6278 4545 6194 4431 6068 4371 6089 3675 6375 + 3016 5993 2997 5942 2859 5732 2802 5591 2798 5438 2820 5318 + 2873 5220 2883 5186 2856 5153 2778 5075 2768 4988 2791 4943 + 2701 4943 2661 4925 2633 4883 2577 4868 2273 4422 2457 4299 + 2763 4274 3001 4305 3128 4328 3203 4230 3216 4124 3173 4028 + 3081 3995 2986 3945 2880 3851 2733 3770 2634 3698 2493 3665 + 2334 3566 2221 3413 2166 3323 2133 3179 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 +3 0 0 3 0 7 49 0 -1 0.000 0 0 0 5 + 3489 1649 3649 1554 3825 1575 3953 1675 4005 1902 + 0.000 1.000 1.000 1.000 0.000 +3 0 0 3 0 7 49 0 -1 0.000 0 0 0 10 + 3278 1680 3254 1569 3149 1539 3009 1544 2883 1665 2696 1865 + 2564 2129 2505 2334 2441 2484 2379 2670 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 0.000 +3 0 0 3 0 31 51 0 20 0.000 0 0 0 71 + 2452 4170 2238 4009 2122 3911 2078 3867 2096 3836 2128 3795 + 2148 3725 2153 3675 2151 3587 2131 3510 2101 3423 2013 3341 + 1954 3332 2041 3258 1914 3207 1843 3180 1773 3140 1668 3097 + 1557 3040 1621 3132 1671 3192 1718 3287 1753 3350 1783 3475 + 1836 3430 1891 3385 1943 3442 2003 3515 2021 3595 2023 3642 + 2006 3702 1953 3735 1921 3767 1873 3730 1833 3695 1791 3665 + 1738 3622 1669 3576 1731 3501 1731 3474 1529 3466 1222 3248 + 1344 3469 1433 3645 1446 3735 1468 3765 1503 3740 1563 3675 + 1616 3722 1703 3792 1758 3842 1786 3927 1718 3977 1518 4045 + 1229 3950 1297 3894 1364 3856 1357 3792 1147 3759 903 3564 + 884 3646 1008 3875 1218 4119 1413 4179 1641 4200 1796 4130 + 1926 4060 1956 4027 2076 4125 2216 4253 2332 4339 + 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000 + 1.000 1.000 1.000 1.000 1.000 1.000 0.000 diff --git a/share/examples/BSD_daemon/beastie.svg b/share/examples/BSD_daemon/beastie.svg new file mode 100644 index 000000000000..9d16e3da42a5 --- /dev/null +++ b/share/examples/BSD_daemon/beastie.svg @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="283.464567pt" height="283.464567pt" viewBox="0 0 283.464567 283.464567" version="1.1"> +<g style="stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;stroke-linecap:butt;stroke-linejoin:miter;fill:none;fill-rule:nonzero;fill-opacity:1;stroke-width:30;" transform="matrix(0.035,0,0,0.035,0,0)"> +<path style="fill:rgb(82%,0%,0%);" d="M 2174 2967 l 5 -11 l 4 -10 l 6 -11 l 6 -12 l 7 -12 l 8 -13 l 9 -12 l 8 -13 l 9 -12 l 10 -13 l 8 -9 l 8 -10 l 8 -11 l 10 -11 l 9 -12 l 10 -12 l 10 -13 l 10 -14 l 10 -13 l 9 -13 l 9 -12 l 8 -13 l 7 -12 l 7 -12 l 5 -12 l 6 -12 l 5 -13 l 5 -13 l 4 -14 l 5 -14 l 4 -15 l 3 -15 l 4 -15 l 4 -15 l 3 -15 l 3 -15 l 3 -15 l 4 -14 l 3 -15 l 4 -16 l 5 -17 l 4 -17 l 5 -18 l 4 -18 l 5 -18 l 4 -18 l 5 -18 l 4 -16 l 3 -16 l 3 -15 l 3 -13 l 2 -13 l 2 -16 l 2 -16 l 0 -44 l -2 -13 l -1 -12 l -2 -12 l -2 -11 l -2 -10 l -2 -9 l -2 -9 l -2 -10 l -2 -11 l -2 -12 l -3 -12 l -2 -13 l -3 -14 l -2 -13 l -3 -14 l -3 -15 l -2 -15 l -3 -13 l -3 -15 l -3 -15 l -2 -16 l -4 -18 l -6 -36 l -3 -18 l -3 -18 l -2 -18 l -3 -17 l -2 -16 l -2 -15 l -1 -14 l -2 -16 l -1 -15 l -1 -16 l -1 -15 l 0 -16 l 1 -15 l 1 -15 l 2 -28 l 2 -13 l 3 -13 l 3 -13 l 3 -12 l 3 -14 l 4 -13 l 4 -15 l 5 -14 l 5 -14 l 4 -14 l 5 -13 l 4 -12 l 4 -11 l 4 -10 l 3 -9 l 3 -9 l 6 -16 l 4 -9 l 4 -8 l 6 -9 l 6 -10 l 7 -10 l 9 -11 l 10 -13 l 8 -9 l 8 -10 l 9 -11 l 10 -12 l 12 -13 l 12 -15 l 13 -14 l 14 -16 l 14 -16 l 15 -16 l 15 -15 l 14 -16 l 15 -15 l 14 -15 l 54 -54 l 14 -12 l 13 -13 l 14 -12 l 15 -13 l 15 -13 l 15 -13 l 15 -13 l 15 -13 l 15 -12 l 15 -13 l 15 -11 l 15 -11 l 14 -11 l 13 -10 l 13 -10 l 14 -9 l 14 -11 l 16 -10 l 15 -11 l 16 -10 l 16 -11 l 16 -10 l 17 -11 l 16 -10 l 17 -10 l 15 -9 l 16 -9 l 15 -9 l 14 -8 l 13 -7 l 13 -7 l 12 -6 l 15 -9 l 16 -7 l 15 -8 l 16 -7 l 15 -6 l 15 -6 l 14 -5 l 14 -4 l 12 -3 l 12 -2 l 11 -1 l 10 0 l 9 1 l 9 1 l 10 3 l 8 3 l 9 4 l 7 4 l 7 5 l 5 6 l 5 6 l 3 5 l 2 12 l -1 6 l -2 7 l -5 8 l -6 8 l -7 9 l -8 9 l -10 9 l -9 9 l -10 8 l -9 10 l -9 7 l -8 9 l -9 9 l -10 10 l -10 10 l -10 11 l -10 11 l -10 11 l -10 11 l -9 11 l -9 10 l -9 11 l -9 10 l -9 11 l -9 12 l -9 12 l -10 12 l -9 12 l -9 12 l -9 12 l -8 11 l -8 10 l -7 10 l -6 9 l -8 11 l -7 10 l -7 10 l -6 10 l -7 10 l -5 10 l -5 9 l -5 9 l -3 8 l -3 8 l -4 10 l -3 11 l -2 11 l -2 13 l -1 12 l -1 12 l -1 12 l 0 23 l 1 13 l 0 13 l 2 14 l 1 13 l 2 13 l 2 11 l 3 11 l 3 9 l 4 10 l 4 8 l 5 9 l 6 7 l 6 6 l 7 5 l 7 4 l 7 2 l 9 2 l 10 1 l 11 -1 l 12 -2 l 13 -2 l 13 -4 l 14 -5 l 10 -4 l 10 -4 l 12 -5 l 12 -5 l 13 -6 l 14 -6 l 15 -7 l 14 -6 l 15 -6 l 15 -6 l 14 -6 l 15 -5 l 12 -5 l 13 -5 l 14 -4 l 15 -5 l 15 -4 l 16 -5 l 17 -4 l 16 -4 l 17 -4 l 17 -3 l 16 -4 l 16 -3 l 16 -2 l 15 -2 l 16 -3 l 16 -2 l 17 -1 l 17 -2 l 19 -2 l 57 -3 l 20 0 l 19 -1 l 19 0 l 18 1 l 18 0 l 17 1 l 15 0 l 16 1 l 17 1 l 17 2 l 18 1 l 18 3 l 20 2 l 20 3 l 20 3 l 63 12 l 42 10 l 21 6 l 21 6 l 36 10 l 19 6 l 19 6 l 42 14 l 21 7 l 22 8 l 22 9 l 22 8 l 44 18 l 21 8 l 21 9 l 19 9 l 19 8 l 18 9 l 17 8 l 16 8 l 15 8 l 20 11 l 20 12 l 18 12 l 18 12 l 17 12 l 17 12 l 15 13 l 14 12 l 13 11 l 12 11 l 11 10 l 9 10 l 9 9 l 8 8 l 10 11 l 10 11 l 10 10 l 10 9 l 10 9 l 9 8 l 10 7 l 9 5 l 9 4 l 10 4 l 8 2 l 9 1 l 11 1 l 11 0 l 12 -1 l 13 -2 l 14 -2 l 14 -3 l 15 -4 l 15 -4 l 15 -5 l 15 -6 l 14 -5 l 15 -6 l 15 -7 l 16 -7 l 17 -8 l 17 -9 l 16 -8 l 17 -9 l 16 -9 l 15 -9 l 14 -8 l 12 -8 l 11 -8 l 10 -7 l 10 -8 l 9 -8 l 8 -9 l 6 -8 l 6 -9 l 8 -20 l 2 -11 l 2 -11 l 1 -11 l 1 -12 l 0 -12 l 1 -12 l 0 -13 l -1 -14 l 0 -15 l -1 -17 l -1 -17 l -1 -18 l -2 -18 l -2 -19 l -6 -36 l -4 -17 l -4 -17 l -4 -16 l -5 -16 l -6 -16 l -7 -17 l -7 -16 l -7 -17 l -8 -17 l -9 -16 l -8 -17 l -9 -15 l -8 -14 l -7 -14 l -8 -12 l -6 -12 l -6 -10 l -8 -14 l -7 -14 l -7 -12 l -5 -12 l -5 -12 l -3 -10 l -2 -9 l -1 -9 l 1 -7 l 1 -6 l 3 -6 l 4 -5 l 6 -6 l 6 -5 l 8 -4 l 9 -4 l 9 -3 l 10 -3 l 10 -1 l 10 -1 l 11 -1 l 11 0 l 13 1 l 13 2 l 14 3 l 14 4 l 14 4 l 13 5 l 14 6 l 12 6 l 9 5 l 10 5 l 9 7 l 11 7 l 10 8 l 11 9 l 12 9 l 12 11 l 12 11 l 12 12 l 12 12 l 12 12 l 12 14 l 12 14 l 10 11 l 10 12 l 11 13 l 11 13 l 12 15 l 12 15 l 12 16 l 13 16 l 12 17 l 13 17 l 12 17 l 12 17 l 11 17 l 11 16 l 10 16 l 9 15 l 10 15 l 8 15 l 9 16 l 9 16 l 8 16 l 8 17 l 8 17 l 7 17 l 7 18 l 7 17 l 6 17 l 6 17 l 6 17 l 5 16 l 4 16 l 5 15 l 4 14 l 3 15 l 4 14 l 3 15 l 4 15 l 3 15 l 3 16 l 4 17 l 2 17 l 3 17 l 2 17 l 2 17 l 2 16 l 1 17 l 1 15 l 0 31 l -1 15 l -1 15 l -1 15 l -2 15 l -2 16 l -3 17 l -4 18 l -4 17 l -5 19 l -6 18 l -6 18 l -7 19 l -7 18 l -8 18 l -16 34 l -9 18 l -9 15 l -9 16 l -10 17 l -10 17 l -11 18 l -12 18 l -13 19 l -14 18 l -13 19 l -15 19 l -14 19 l -15 18 l -14 18 l -15 17 l -14 16 l -15 16 l -14 15 l -14 15 l -14 14 l -15 14 l -15 13 l -15 14 l -16 14 l -17 14 l -16 14 l -17 13 l -17 13 l -16 13 l -16 13 l -16 11 l -15 12 l -15 10 l -14 10 l -13 9 l -12 9 l -12 9 l -17 12 l -17 11 l -16 12 l -15 10 l -15 11 l -14 9 l -13 9 l -11 8 l -10 6 l -8 6 l -7 4 l -5 3 l -4 2 l -6 4 l -2 1 l -1 2 l -1 1 l -1 3 l 0 6 l 1 5 l 0 5 l 1 6 l 1 8 l 0 9 l 1 9 l 0 67 l -1 18 l 0 18 l -1 20 l -2 19 l -1 20 l -2 19 l -1 20 l -2 19 l -3 18 l -2 19 l -3 18 l -3 19 l -3 19 l -4 19 l -4 20 l -5 20 l -5 20 l -6 21 l -5 20 l -6 20 l -7 19 l -6 19 l -6 18 l -7 17 l -7 16 l -6 16 l -8 16 l -7 15 l -8 16 l -9 16 l -9 17 l -10 16 l -10 17 l -11 17 l -11 17 l -11 16 l -12 16 l -11 15 l -12 15 l -12 15 l -12 14 l -11 14 l -13 14 l -13 14 l -13 14 l -14 15 l -15 15 l -14 15 l -16 15 l -15 16 l -15 15 l -14 15 l -40 40 l -11 12 l -11 11 l -9 11 l -12 13 l -11 13 l -11 13 l -9 13 l -9 13 l -8 12 l -7 12 l -6 11 l -5 11 l -8 20 l -3 9 l -4 11 l -3 11 l -2 12 l -3 12 l -2 13 l -2 13 l -1 12 l 0 46 l 1 12 l 2 12 l 2 13 l 3 13 l 3 14 l 3 13 l 4 12 l 4 11 l 5 12 l 5 11 l 5 11 l 7 12 l 6 13 l 8 13 l 7 12 l 7 13 l 7 12 l 7 11 l 6 11 l 6 12 l 6 11 l 6 13 l 6 13 l 6 14 l 6 14 l 5 14 l 5 14 l 5 14 l 4 14 l 3 10 l 3 11 l 3 11 l 3 12 l 2 13 l 3 13 l 3 15 l 3 14 l 2 16 l 2 15 l 2 16 l 2 15 l 2 16 l 2 17 l 1 14 l 1 16 l 1 16 l 1 17 l 1 18 l 1 18 l 1 19 l 0 19 l 1 19 l 0 37 l 1 17 l 0 16 l -1 16 l 0 29 l -1 17 l 0 17 l -1 17 l -2 16 l -1 16 l -2 16 l -2 15 l -3 13 l -2 13 l -3 12 l -3 11 l -2 11 l -4 12 l -5 13 l -4 13 l -5 13 l -5 14 l -5 13 l -5 13 l -4 12 l -3 12 l -3 11 l -2 9 l -1 9 l -1 10 l -1 11 l 0 12 l 1 12 l 2 13 l 2 14 l 2 15 l 4 15 l 4 16 l 4 17 l 4 13 l 4 15 l 5 15 l 5 17 l 6 18 l 7 19 l 7 19 l 7 21 l 8 21 l 8 20 l 9 21 l 8 21 l 9 19 l 9 20 l 9 19 l 9 18 l 8 16 l 8 17 l 9 16 l 9 17 l 10 18 l 11 17 l 11 18 l 11 17 l 11 18 l 12 17 l 13 17 l 12 17 l 12 16 l 12 15 l 13 15 l 12 14 l 12 14 l 12 13 l 26 26 l 14 13 l 14 12 l 15 13 l 15 14 l 16 13 l 17 13 l 17 13 l 17 12 l 18 13 l 17 12 l 17 11 l 17 11 l 17 10 l 17 11 l 16 9 l 16 10 l 17 9 l 17 9 l 17 9 l 18 9 l 19 10 l 19 9 l 20 9 l 21 10 l 21 9 l 42 18 l 21 8 l 21 8 l 20 8 l 20 7 l 40 14 l 19 6 l 36 12 l 19 5 l 19 6 l 20 5 l 21 6 l 21 5 l 22 6 l 22 6 l 23 5 l 22 6 l 46 10 l 22 6 l 23 5 l 21 4 l 22 5 l 21 5 l 21 4 l 21 5 l 21 4 l 21 5 l 22 4 l 22 5 l 23 5 l 23 5 l 24 5 l 25 5 l 24 5 l 24 5 l 25 5 l 24 5 l 46 10 l 22 5 l 21 5 l 20 4 l 20 5 l 19 4 l 18 4 l 22 5 l 21 5 l 22 6 l 22 5 l 21 5 l 22 6 l 21 5 l 21 6 l 20 5 l 19 6 l 19 5 l 17 5 l 17 5 l 15 5 l 15 5 l 14 4 l 32 10 l 15 6 l 16 5 l 16 6 l 16 6 l 16 7 l 15 6 l 15 6 l 15 7 l 13 6 l 13 7 l 13 6 l 12 7 l 12 6 l 12 8 l 13 7 l 12 8 l 13 9 l 13 9 l 13 9 l 12 10 l 12 10 l 11 9 l 10 10 l 10 9 l 9 9 l 8 9 l 9 11 l 8 11 l 8 12 l 8 12 l 7 13 l 7 13 l 6 13 l 5 13 l 5 13 l 3 11 l 4 12 l 3 11 l 2 13 l 2 13 l 2 14 l 1 15 l -1 14 l -1 15 l -3 14 l -4 14 l -5 13 l -6 12 l -6 11 l -7 10 l -8 12 l -9 11 l -10 12 l -11 12 l -12 11 l -12 11 l -11 10 l -12 10 l -11 9 l -11 8 l -9 7 l -10 7 l -10 6 l -11 7 l -11 6 l -13 6 l -13 7 l -13 6 l -15 5 l -15 6 l -15 5 l -16 5 l -17 5 l -17 5 l -16 4 l -18 5 l -18 4 l -20 5 l -20 4 l -22 5 l -22 4 l -22 5 l -21 4 l -22 5 l -20 4 l -19 3 l -18 4 l -16 3 l -15 3 l -13 2 l -16 3 l -14 3 l -12 2 l -10 3 l -9 2 l -8 2 l -5 3 l -4 2 l -3 3 l -2 3 l 0 6 l 1 8 l 2 11 l 3 12 l 3 12 l 2 11 l 0 9 l -2 4 l -2 3 l -3 4 l -6 2 l -7 2 l -9 2 l -11 2 l -14 1 l -15 0 l -17 1 l -10 0 l -12 1 l -41 0 l -17 1 l -36 0 l -20 1 l -20 0 l -21 1 l -43 0 l -22 1 l -22 0 l -23 1 l -22 0 l -22 1 l -21 1 l -22 0 l -22 1 l -23 1 l -24 0 l -24 1 l -26 1 l -25 1 l -27 1 l -78 3 l -50 2 l -46 2 l -22 1 l -21 1 l -20 1 l -19 1 l -46 2 l -22 2 l -21 1 l -22 1 l -21 1 l -20 2 l -19 1 l -18 1 l -18 1 l -16 1 l -14 0 l -13 1 l -12 0 l -11 1 l -37 0 l -11 -1 l -10 -1 l -9 -1 l -7 -2 l -4 -2 l -4 -2 l -1 -2 l -1 -3 l 0 -2 l 2 -3 l 3 -4 l 5 -4 l 7 -6 l 9 -6 l 12 -8 l 15 -9 l 17 -11 l 20 -12 l 23 -13 l 26 -14 l 15 -9 l 17 -9 l 18 -10 l 19 -11 l 20 -11 l 22 -12 l 23 -12 l 23 -13 l 25 -14 l 25 -13 l 26 -15 l 25 -14 l 26 -14 l 25 -14 l 25 -13 l 25 -14 l 23 -13 l 23 -12 l 21 -12 l 21 -11 l 19 -11 l 19 -10 l 24 -14 l 24 -13 l 22 -13 l 21 -12 l 21 -12 l 20 -12 l 19 -11 l 17 -10 l 17 -10 l 15 -9 l 14 -9 l 13 -8 l 11 -7 l 11 -7 l 9 -6 l 9 -5 l 12 -9 l 12 -8 l 12 -8 l 10 -8 l 10 -6 l 10 -6 l 8 -4 l 7 -3 l 6 -2 l 11 0 l 5 1 l 5 3 l 5 4 l 5 4 l 15 18 l 4 6 l 5 7 l 5 8 l 6 9 l 6 10 l 6 10 l 6 10 l 6 11 l 5 9 l 5 10 l 4 9 l 4 10 l 5 10 l 4 10 l 4 10 l 4 9 l 4 8 l 3 8 l 3 6 l 4 6 l 4 5 l 5 5 l 6 5 l 7 5 l 7 3 l 9 3 l 9 2 l 11 1 l 20 0 l 12 -1 l 14 -1 l 14 -2 l 15 -2 l 16 -2 l 16 -3 l 15 -3 l 15 -4 l 14 -3 l 13 -3 l 14 -4 l 13 -4 l 13 -4 l 14 -4 l 14 -5 l 13 -5 l 14 -5 l 12 -5 l 13 -5 l 11 -5 l 11 -5 l 11 -5 l 12 -7 l 12 -6 l 13 -8 l 12 -7 l 12 -8 l 12 -9 l 10 -8 l 9 -8 l 7 -7 l 6 -7 l 4 -6 l 3 -6 l 3 -7 l 2 -7 l 1 -6 l 0 -8 l -1 -7 l -2 -7 l -2 -7 l -3 -7 l -4 -7 l -10 -14 l -6 -8 l -7 -8 l -9 -8 l -9 -9 l -10 -9 l -11 -9 l -12 -8 l -11 -9 l -12 -8 l -13 -7 l -12 -7 l -20 -10 l -11 -5 l -11 -5 l -13 -6 l -14 -5 l -15 -5 l -16 -5 l -16 -5 l -36 -10 l -19 -4 l -19 -5 l -20 -4 l -20 -4 l -21 -4 l -18 -3 l -19 -3 l -20 -4 l -21 -3 l -23 -3 l -23 -4 l -24 -3 l -25 -4 l -26 -4 l -27 -3 l -27 -4 l -26 -4 l -27 -3 l -26 -4 l -26 -3 l -25 -4 l -24 -3 l -24 -4 l -23 -3 l -22 -3 l -23 -4 l -22 -3 l -44 -8 l -23 -3 l -23 -4 l -23 -4 l -23 -4 l -23 -5 l -22 -4 l -23 -4 l -22 -4 l -21 -4 l -21 -5 l -20 -4 l -19 -4 l -18 -3 l -17 -4 l -17 -4 l -17 -3 l -20 -5 l -21 -5 l -20 -4 l -20 -5 l -21 -5 l -21 -6 l -42 -10 l -21 -6 l -20 -5 l -19 -5 l -19 -6 l -18 -5 l -17 -5 l -17 -4 l -32 -10 l -17 -5 l -16 -5 l -17 -6 l -18 -5 l -17 -6 l -18 -6 l -17 -6 l -18 -6 l -17 -6 l -16 -5 l -16 -6 l -15 -5 l -14 -5 l -14 -5 l -13 -5 l -14 -5 l -15 -6 l -14 -5 l -15 -6 l -15 -6 l -15 -6 l -14 -6 l -15 -6 l -13 -6 l -14 -6 l -12 -6 l -12 -6 l -11 -6 l -11 -6 l -13 -8 l -13 -7 l -13 -8 l -26 -18 l -14 -9 l -13 -9 l -13 -9 l -12 -9 l -12 -8 l -11 -8 l -11 -7 l -10 -8 l -11 -7 l -11 -8 l -11 -8 l -12 -8 l -11 -8 l -12 -9 l -11 -8 l -10 -8 l -11 -8 l -9 -8 l -10 -8 l -11 -10 l -11 -10 l -12 -11 l -12 -11 l -11 -12 l -12 -10 l -11 -10 l -10 -8 l -9 -7 l -8 -5 l -7 -4 l -6 -3 l -8 -1 l -9 -1 l -10 2 l -12 2 l -15 4 l -17 5 l -19 7 l -21 9 l -24 9 l -27 11 l -15 6 l -16 7 l -17 7 l -19 7 l -19 7 l -21 8 l -22 8 l -24 8 l -24 8 l -26 8 l -26 8 l -27 8 l -27 7 l -28 7 l -28 6 l -29 5 l -28 5 l -28 4 l -27 4 l -27 2 l -27 2 l -53 0 l -26 -1 l -26 -3 l -26 -3 l -26 -4 l -26 -6 l -27 -6 l -27 -7 l -27 -8 l -27 -9 l -28 -10 l -27 -10 l -27 -11 l -52 -22 l -25 -12 l -24 -12 l -23 -11 l -21 -12 l -21 -11 l -20 -11 l -18 -11 l -17 -10 l -15 -9 l -15 -9 l -13 -9 l -21 -13 l -19 -13 l -16 -11 l -15 -11 l -13 -10 l -11 -10 l -9 -9 l -9 -8 l -7 -8 l -6 -8 l -5 -8 l -5 -7 l -10 -16 l -5 -9 l -6 -10 l -7 -11 l -7 -12 l -8 -12 l -8 -13 l -9 -14 l -9 -14 l -8 -14 l -8 -14 l -8 -13 l -8 -13 l -7 -12 l -6 -11 l -8 -14 l -7 -13 l -6 -13 l -7 -14 l -6 -14 l -5 -13 l -6 -14 l -4 -13 l -4 -12 l -4 -12 l -3 -12 l -2 -11 l -2 -11 l -2 -12 l -2 -12 l -1 -13 l -1 -13 l -1 -13 l -1 -13 l 0 -37 l 1 -11 l 0 -10 l 1 -13 l 2 -13 l 1 -12 l 2 -14 l 2 -13 l 3 -13 l 3 -12 l 3 -11 l 3 -11 l 3 -10 l 5 -13 l 5 -12 l 5 -13 l 6 -13 l 6 -12 l 5 -11 l 5 -9 l 4 -8 l 4 -10 l 4 -9 l 2 -7 l 1 -8 l 1 -6 l -1 -5 l -2 -5 l -3 -6 l -5 -7 l -5 -7 l -7 -7 l -7 -8 l -7 -7 l -7 -8 l -8 -9 l -9 -9 l -8 -10 l -7 -10 l -7 -10 l -6 -9 l -4 -10 l -4 -10 l -3 -11 l -3 -11 l -1 -10 l -1 -10 l 0 -9 l 1 -8 l 0 -7 l 2 -7 l 1 -7 l 1 -6 l 0 -6 l -1 -5 l -2 -4 l -3 -2 l -6 -3 l -10 -3 l -11 -1 l -13 -2 l -12 -1 l -11 -1 l -9 -2 l -9 -2 l -9 -3 l -14 -8 l -5 -4 l -5 -5 l -6 -6 l -5 -6 l -6 -6 l -6 -6 l -7 -4 l -4 -3 l -4 -3 l -6 -4 l -7 -5 l -8 -7 l -10 -9 l -11 -11 l -13 -14 l -14 -16 l -15 -20 l -10 -12 l -10 -14 l -11 -15 l -12 -16 l -12 -17 l -12 -19 l -13 -20 l -13 -20 l -12 -20 l -13 -21 l -11 -21 l -11 -21 l -10 -19 l -9 -19 l -8 -18 l -6 -17 l -5 -16 l -4 -15 l -2 -13 l -1 -12 l 0 -12 l 1 -11 l 2 -11 l 3 -10 l 4 -10 l 5 -9 l 6 -9 l 7 -9 l 8 -8 l 8 -7 l 9 -7 l 10 -6 l 10 -5 l 10 -6 l 11 -4 l 10 -4 l 11 -4 l 11 -4 l 15 -4 l 15 -4 l 15 -3 l 17 -3 l 17 -3 l 36 -6 l 19 -2 l 19 -2 l 19 -1 l 19 -2 l 18 -1 l 17 0 l 17 -1 l 32 0 l 17 1 l 18 0 l 54 3 l 19 2 l 18 2 l 17 1 l 17 2 l 16 2 l 15 2 l 14 2 l 13 2 l 13 2 l 32 4 l 15 3 l 16 1 l 15 2 l 27 0 l 11 -1 l 11 -2 l 9 -3 l 9 -4 l 9 -5 l 9 -7 l 9 -7 l 8 -9 l 7 -9 l 7 -10 l 6 -9 l 5 -10 l 5 -9 l 3 -10 l 4 -10 l 3 -10 l 2 -11 l 2 -11 l 1 -11 l 0 -31 l -1 -9 l -2 -12 l -4 -12 l -4 -12 l -5 -12 l -6 -12 l -7 -10 l -7 -10 l -15 -15 l -10 -6 l -10 -6 l -11 -6 l -12 -6 l -12 -5 l -11 -5 l -10 -5 l -9 -4 l -9 -4 l -10 -5 l -10 -5 l -10 -5 l -10 -6 l -10 -6 l -10 -7 l -10 -6 l -9 -6 l -9 -7 l -10 -8 l -10 -8 l -12 -9 l -11 -9 l -12 -9 l -12 -9 l -12 -9 l -11 -9 l -12 -8 l -10 -7 l -10 -6 l -11 -7 l -11 -7 l -12 -8 l -12 -7 l -12 -7 l -12 -7 l -12 -7 l -10 -6 l -10 -7 l -10 -5 l -11 -8 l -11 -7 l -12 -7 l -11 -7 l -12 -8 l -12 -7 l -12 -7 l -11 -6 l -11 -5 l -11 -5 l -9 -4 l -10 -4 l -11 -4 l -11 -4 l -12 -4 l -12 -4 l -12 -4 l -13 -5 l -12 -4 l -12 -5 l -12 -4 l -11 -5 l -12 -5 l -12 -6 l -12 -7 l -13 -7 l -13 -8 l -14 -8 l -13 -9 l -13 -9 l -13 -10 l -12 -9 l -11 -9 l -10 -10 l -11 -10 l -10 -10 l -10 -11 l -11 -12 l -10 -12 l -10 -12 l -10 -13 l -9 -12 l -9 -11 l -8 -11 l -7 -10 l -6 -9 l -8 -11 l -7 -11 l -7 -11 l -7 -11 l -7 -12 l -6 -11 l -5 -11 l -6 -11 l -4 -10 l -4 -11 l -4 -11 l -4 -12 l -4 -13 l -4 -13 l -6 -28 l -3 -14 l -3 -12 l -1 -12 l -2 -11 l -1 -11 l -1 -11 l -1 -10 l 0 -34 l 1 -10 l 1 -11 l 2 -9 l 1 -10 l 2 -10 l 2 -11 l 3 -12 l 3 -12 l 3 -12 l 4 -13 l 4 -12 l 4 -12 l 4 -11 Z" /> +<path style="fill:rgb(0%,69%,0%);" d="M 2420 6449 l 12 -1 l 12 0 l 13 -1 l 14 -1 l 13 0 l 14 -1 l 50 0 l 12 -1 l 109 0 l 10 -1 l 21 0 l 11 -1 l 11 -1 l 11 -1 l 10 -1 l 9 -2 l 9 -2 l 9 -2 l 10 -4 l 10 -5 l 11 -5 l 11 -6 l 10 -6 l 11 -6 l 10 -5 l 11 -5 l 10 -5 l 11 -4 l 12 -5 l 13 -5 l 13 -4 l 12 -4 l 11 -4 l 11 -4 l 10 -4 l 10 -4 l 10 -4 l 10 -5 l 10 -4 l 9 -5 l 7 -4 l 8 -3 l 8 -5 l 8 -6 l 8 -6 l 6 -6 l 5 -8 l 4 -7 l 1 -7 l 1 -8 l 0 -19 l -1 -10 l -2 -9 l -2 -9 l -2 -8 l -3 -8 l -3 -9 l -3 -8 l -4 -9 l -4 -8 l -4 -9 l -4 -8 l -3 -8 l -4 -9 l -4 -10 l -4 -10 l -4 -11 l -3 -12 l -4 -10 l -3 -11 l -2 -9 l -4 -12 l -3 -13 l -2 -12 l -1 -11 l 0 -9 l 1 -6 l 1 -3 l 1 -2 l 3 -2 l 2 -2 l 4 0 l 3 -1 l 8 2 l 5 1 l 4 2 l 8 3 l 8 5 l 10 6 l 10 6 l 8 7 l 8 6 l 7 7 l 8 6 l 7 7 l 8 6 l 7 5 l 8 3 l 8 1 l 10 0 l 11 -1 l 11 -1 l 11 -2 l 11 -1 l 8 -1 l 9 -1 l 36 0 l 8 1 l 17 0 l 10 1 l 11 1 l 10 2 l 16 4 l 7 3 l 8 4 l 7 6 l 8 6 l 7 6 l 6 7 l 7 6 l 7 8 l 8 8 l 8 7 l 9 5 l 8 4 l 9 2 l 20 0 l 10 -2 l 9 -1 l 9 -1 l 8 -1 l 8 -1 l 9 1 l 7 2 l 7 2 l 5 4 l 5 5 l 4 6 l 5 8 l 4 9 l 3 9 l 3 9 l 2 7 l 4 16 l 2 9 l 2 8 l 2 9 l 1 7 l 1 8 l 1 9 l 1 9 l 2 8 l 1 6 l 2 3 l 2 0 l 2 -3 l 3 -6 l 4 -9 l 4 -11 l 4 -12 l 4 -11 l 3 -9 l 4 -9 l 3 -10 l 8 -20 l 4 -10 l 4 -9 l 4 -8 l 8 -18 l 5 -9 l 5 -8 l 5 -9 l 6 -8 l 5 -6 l 6 -6 l 5 -6 l 7 -5 l 7 -5 l 8 -5 l 9 -4 l 16 -6 l 8 -2 l 7 -2 l 9 -2 l 9 -1 l 18 -2 l 18 0 l 8 1 l 7 0 l 8 1 l 9 2 l 8 2 l 9 2 l 8 3 l 8 2 l 8 4 l 7 3 l 8 4 l 8 5 l 9 5 l 9 5 l 8 6 l 8 5 l 8 5 l 7 5 l 8 6 l 8 6 l 8 6 l 7 6 l 7 6 l 12 12 l 6 7 l 6 7 l 5 6 l 4 5 l 3 4 l 3 1 l 2 -2 l 2 -5 l 2 -7 l 3 -7 l 3 -7 l 3 -4 l 3 -3 l 4 -3 l 5 -3 l 6 -2 l 6 -2 l 7 -2 l 7 -1 l 8 -1 l 8 -1 l 10 0 l 11 -1 l 22 0 l 10 -1 l 21 0 l 11 -1 l 11 -1 l 12 -1 l 12 -1 l 11 -1 l 11 -2 l 20 -4 l 10 -3 l 11 -3 l 11 -3 l 11 -4 l 10 -3 l 10 -3 l 9 -3 l 8 -3 l 8 -3 l 9 -3 l 9 -4 l 9 -3 l 9 -3 l 8 -4 l 8 -3 l 8 -4 l 9 -3 l 9 -4 l 9 -3 l 9 -2 l 9 0 l 8 1 l 7 3 l 7 4 l 6 7 l 7 9 l 7 11 l 7 12 l 6 13 l 6 12 l 6 13 l 5 10 l 5 11 l 5 12 l 6 12 l 6 13 l 6 13 l 6 13 l 6 12 l 5 12 l 6 12 l 4 10 l 5 10 l 4 11 l 5 12 l 6 11 l 5 13 l 5 12 l 5 12 l 4 12 l 5 11 l 4 11 l 4 11 l 4 11 l 4 11 l 4 12 l 4 12 l 4 12 l 4 13 l 4 12 l 3 12 l 4 12 l 3 11 l 4 10 l 3 11 l 4 11 l 4 12 l 4 13 l 4 12 l 4 12 l 4 12 l 4 11 l 4 10 l 3 9 l 3 9 l 2 7 l 2 8 l 2 7 l 1 7 l 0 8 l -1 8 l -2 7 l -4 8 l -4 7 l -6 8 l -6 6 l -6 6 l -8 7 l -8 8 l -11 8 l -12 8 l -13 10 l -15 9 l -16 10 l -18 10 l -18 10 l -19 11 l -21 10 l -21 11 l -14 6 l -16 8 l -16 7 l -17 7 l -18 8 l -19 8 l -20 9 l -21 8 l -21 9 l -23 9 l -23 9 l -23 9 l -24 8 l -23 9 l -24 8 l -23 8 l -24 8 l -23 7 l -44 14 l -23 7 l -21 6 l -22 6 l -23 6 l -22 6 l -24 5 l -23 6 l -25 5 l -25 5 l -25 5 l -26 5 l -54 10 l -27 4 l -26 4 l -27 4 l -27 3 l -26 4 l -26 3 l -26 2 l -25 3 l -25 2 l -24 2 l -25 2 l -23 2 l -23 1 l -72 3 l -25 1 l -52 2 l -54 0 l -27 1 l -26 0 l -27 -1 l -53 0 l -50 -2 l -24 0 l -23 -1 l -22 -1 l -22 -2 l -21 -1 l -20 -1 l -19 -2 l -26 -2 l -25 -3 l -24 -3 l -25 -3 l -24 -3 l -24 -4 l -24 -5 l -24 -5 l -23 -5 l -22 -5 l -42 -12 l -19 -7 l -36 -14 l -16 -7 l -15 -7 l -15 -8 l -14 -8 l -14 -9 l -15 -9 l -14 -10 l -14 -11 l -14 -11 l -14 -12 l -14 -13 l -14 -13 l -14 -13 l -14 -14 l -13 -14 l -13 -13 l -12 -14 l -12 -14 l -12 -13 l -12 -14 l -11 -13 l -13 -16 l -13 -16 l -13 -17 l -14 -17 l -13 -17 l -13 -18 l -13 -18 l -12 -18 l -20 -34 l -8 -16 l -7 -15 l -4 -14 l -4 -13 l -1 -11 l 1 -11 l 2 -11 l 5 -10 l 7 -9 l 10 -9 l 11 -8 l 13 -7 l 15 -6 l 16 -6 l 16 -5 l 16 -4 l 16 -3 l 15 -3 l 15 -2 l 14 -2 l 15 -3 l 15 -2 l 15 -2 l 28 -4 l 14 -1 l 13 -2 l 12 -1 l 12 -1 l 11 -1 l 10 -1 Z" /> +<path style="fill:rgb(100%,84%,0%);" d="M 2452 4170 l -1 0 l -3 -3 l -9 -7 l -15 -11 l -19 -14 l -21 -17 l -22 -16 l -21 -16 l -19 -15 l -17 -12 l -15 -12 l -13 -10 l -12 -9 l -11 -8 l -12 -10 l -12 -10 l -12 -9 l -12 -10 l -11 -9 l -11 -9 l -10 -9 l -10 -8 l -9 -7 l -8 -7 l -7 -6 l -6 -6 l -9 -8 l -8 -7 l -7 -8 l -7 -6 l -5 -7 l -5 -5 l -3 -5 l -2 -5 l -1 -6 l 0 -5 l 2 -6 l 2 -6 l 4 -6 l 3 -6 l 4 -5 l 10 -14 l 5 -8 l 5 -9 l 4 -8 l 3 -6 l 6 -16 l 2 -8 l 3 -9 l 2 -8 l 2 -8 l 2 -7 l 1 -9 l 2 -9 l 1 -10 l 1 -11 l 1 -10 l 0 -38 l -1 -11 l 0 -11 l -1 -10 l -1 -11 l -1 -9 l -1 -10 l -2 -9 l -2 -11 l -3 -10 l -2 -11 l -3 -10 l -3 -10 l -3 -10 l -3 -9 l -3 -10 l -4 -11 l -5 -12 l -5 -11 l -5 -11 l -6 -10 l -7 -10 l -5 -8 l -7 -8 l -7 -8 l -24 -24 l -8 -7 l -8 -6 l -7 -5 l -7 -5 l -8 -5 l -16 -8 l -6 -3 l -6 -4 l -3 -4 l -1 -3 l 0 -5 l 3 -5 l 4 -6 l 5 -8 l 6 -8 l 5 -8 l 4 -9 l 1 -8 l -1 -7 l -3 -7 l -7 -7 l -10 -7 l -11 -7 l -13 -7 l -13 -6 l -13 -5 l -12 -5 l -11 -4 l -11 -5 l -10 -4 l -11 -4 l -10 -4 l -10 -5 l -9 -3 l -8 -4 l -8 -4 l -9 -4 l -9 -5 l -10 -5 l -10 -6 l -10 -5 l -10 -5 l -10 -4 l -8 -4 l -9 -4 l -9 -5 l -11 -4 l -10 -5 l -11 -5 l -11 -4 l -11 -5 l -10 -5 l -10 -4 l -12 -6 l -13 -6 l -13 -6 l -13 -5 l -11 -5 l -8 -2 l -7 -1 l -4 1 l -1 3 l 0 5 l 3 7 l 5 9 l 6 9 l 6 10 l 7 10 l 7 9 l 6 8 l 7 9 l 7 9 l 7 9 l 6 9 l 7 9 l 6 9 l 6 9 l 5 9 l 6 10 l 6 11 l 6 12 l 12 22 l 5 10 l 5 10 l 5 9 l 4 9 l 5 9 l 5 10 l 5 10 l 4 11 l 8 20 l 4 12 l 4 12 l 4 13 l 4 13 l 5 12 l 5 11 l 4 8 l 5 6 l 4 3 l 4 1 l 10 0 l 5 -2 l 6 -3 l 10 -8 l 5 -4 l 5 -4 l 9 -7 l 9 -7 l 9 -6 l 10 -5 l 9 -3 l 9 0 l 6 1 l 6 3 l 7 5 l 7 5 l 14 14 l 7 7 l 6 8 l 7 7 l 7 9 l 7 9 l 7 9 l 7 10 l 7 9 l 5 9 l 5 9 l 8 18 l 4 10 l 3 10 l 2 10 l 2 10 l 2 8 l 1 8 l 2 9 l 1 9 l 0 28 l -1 8 l -4 18 l -3 10 l -4 9 l -4 9 l -5 8 l -6 6 l -7 7 l -8 7 l -16 12 l -6 5 l -7 5 l -6 5 l -7 4 l -6 4 l -7 2 l -6 1 l -6 -2 l -7 -3 l -8 -4 l -8 -5 l -8 -6 l -7 -6 l -6 -5 l -7 -6 l -8 -6 l -7 -6 l -7 -6 l -6 -5 l -7 -5 l -7 -5 l -7 -6 l -16 -12 l -7 -5 l -5 -4 l -6 -5 l -7 -5 l -7 -6 l -7 -6 l -8 -5 l -7 -5 l -7 -5 l -7 -6 l -7 -5 l -8 -6 l -7 -7 l -6 -6 l -5 -7 l -3 -7 l -1 -7 l 0 -7 l 2 -8 l 4 -8 l 5 -9 l 5 -9 l 5 -8 l 5 -7 l 4 -6 l 2 -4 l 1 -3 l 2 -4 l 0 -7 l -1 -2 l -1 -2 l -4 -2 l -2 -2 l -2 -1 l -3 -1 l -4 -1 l -3 -1 l -4 -1 l -5 -1 l -8 -1 l -10 -1 l -11 -2 l -14 -2 l -15 -2 l -16 -3 l -18 -4 l -18 -5 l -19 -5 l -18 -6 l -19 -7 l -19 -8 l -17 -8 l -18 -9 l -18 -9 l -19 -11 l -19 -10 l -19 -11 l -19 -11 l -18 -10 l -16 -9 l -15 -7 l -13 -7 l -11 -4 l -9 -3 l -7 -1 l -6 1 l -3 3 l -2 5 l 0 7 l 2 9 l 3 10 l 4 12 l 5 12 l 7 14 l 6 13 l 7 14 l 7 14 l 8 13 l 7 14 l 7 15 l 8 15 l 8 15 l 8 16 l 8 15 l 8 16 l 7 15 l 7 14 l 6 14 l 5 12 l 5 11 l 4 11 l 6 14 l 4 15 l 4 14 l 4 13 l 3 12 l 2 10 l 3 9 l 4 14 l 2 5 l 3 6 l 6 8 l 3 3 l 6 2 l 5 0 l 5 -2 l 6 -4 l 7 -4 l 7 -6 l 7 -7 l 6 -5 l 13 -13 l 7 -6 l 8 -6 l 14 -8 l 7 -1 l 6 -1 l 14 4 l 8 5 l 8 5 l 8 6 l 8 6 l 16 14 l 9 7 l 10 8 l 11 9 l 10 9 l 10 8 l 9 8 l 9 7 l 8 6 l 8 7 l 7 8 l 8 7 l 7 8 l 7 8 l 5 7 l 6 8 l 4 8 l 4 9 l 4 9 l 3 11 l 2 10 l 1 9 l 0 9 l -2 8 l -3 8 l -5 7 l -6 8 l -9 8 l -11 7 l -12 7 l -13 7 l -15 7 l -9 4 l -10 4 l -11 4 l -12 4 l -13 4 l -13 4 l -15 4 l -15 3 l -16 3 l -16 2 l -15 1 l -16 1 l -32 0 l -16 -1 l -17 -2 l -17 -3 l -18 -4 l -19 -4 l -18 -4 l -18 -5 l -18 -6 l -16 -5 l -15 -6 l -13 -6 l -12 -5 l -9 -5 l -8 -5 l -5 -4 l -4 -3 l -3 -4 l -3 -3 l -2 -3 l -1 -4 l -1 -3 l 0 -6 l 1 -4 l 2 -3 l 1 -3 l 3 -3 l 2 -3 l 3 -2 l 3 -3 l 3 -2 l 3 -3 l 6 -4 l 8 -5 l 8 -6 l 8 -5 l 8 -6 l 7 -6 l 7 -6 l 5 -6 l 4 -5 l 2 -4 l 1 -5 l 1 -4 l 0 -10 l -2 -5 l -6 -10 l -5 -5 l -5 -4 l -7 -4 l -8 -4 l -9 -3 l -10 -4 l -12 -4 l -14 -4 l -15 -5 l -16 -5 l -18 -5 l -17 -6 l -18 -6 l -18 -7 l -17 -8 l -18 -8 l -30 -16 l -16 -10 l -16 -10 l -17 -10 l -16 -11 l -17 -11 l -15 -10 l -16 -10 l -14 -9 l -12 -8 l -12 -7 l -10 -6 l -9 -4 l -5 -2 l -12 -3 l -10 0 l -2 1 l -3 1 l -2 1 l -4 4 l -1 3 l -2 6 l 0 3 l -1 4 l 0 4 l 1 4 l 0 5 l 1 4 l 2 10 l 2 5 l 1 5 l 2 6 l 4 10 l 4 11 l 5 13 l 7 13 l 7 15 l 8 15 l 8 16 l 10 17 l 9 16 l 10 17 l 11 16 l 10 16 l 11 16 l 10 16 l 10 13 l 10 14 l 11 14 l 11 15 l 12 14 l 13 15 l 12 15 l 14 15 l 13 15 l 13 14 l 13 13 l 13 12 l 13 12 l 12 10 l 12 10 l 12 9 l 13 10 l 13 9 l 14 8 l 15 8 l 14 8 l 16 7 l 15 6 l 15 6 l 16 5 l 15 4 l 14 4 l 15 4 l 14 3 l 14 3 l 13 2 l 15 2 l 15 3 l 15 2 l 16 2 l 17 1 l 32 2 l 16 1 l 31 0 l 14 -1 l 13 -1 l 13 -1 l 14 -2 l 15 -3 l 14 -3 l 15 -4 l 15 -5 l 14 -5 l 14 -5 l 14 -6 l 13 -6 l 12 -5 l 12 -6 l 11 -5 l 13 -6 l 13 -7 l 13 -7 l 14 -7 l 13 -7 l 13 -7 l 11 -7 l 11 -6 l 9 -5 l 7 -5 l 7 -4 l 7 -5 l 6 -4 l 6 -3 l 6 -3 l 6 -1 l 5 -1 l 6 0 l 6 1 l 14 6 l 9 5 l 9 7 l 11 7 l 12 9 l 12 9 l 12 10 l 12 10 l 12 11 l 12 10 l 10 9 l 11 9 l 11 10 l 11 10 l 12 10 l 12 11 l 12 10 l 12 11 l 11 10 l 11 9 l 10 9 l 10 8 l 10 8 l 10 8 l 10 9 l 12 9 l 13 10 l 14 10 l 15 12 l 13 10 l 12 9 l 7 5 l 3 3 l 1 0" /> +<path d="M 2876 5202 l 1 1 l 3 4 l 7 10 l 10 14 l 11 15 l 11 13 l 9 12 l 8 10 l 7 8 l 6 7 l 8 8 l 8 8 l 9 8 l 9 7 l 10 7 l 9 7 l 9 6 l 9 5 l 9 6 l 10 6 l 11 6 l 12 7 l 11 6 l 11 6 l 10 4 l 10 5 l 9 3 l 9 4 l 10 3 l 9 3 l 10 2 l 8 2 l 9 2 l 7 2 l 8 2 l 8 2 l 8 1 l 9 2 l 9 2 l 9 2 l 8 1 l 8 1 l 8 1 l 9 1 l 9 1 l 9 1 l 17 0 l 8 1 l 15 0 l 8 -1 l 10 0 l 10 -1 l 6 -1 l 1 0" /> +<path d="M 3161 5427 l 1 0 l 4 3 l 10 6 l 16 10 l 19 11 l 20 12 l 18 11 l 17 9 l 14 8 l 13 7 l 10 5 l 11 5 l 22 10 l 11 4 l 12 4 l 11 3 l 11 3 l 11 2 l 10 3 l 10 1 l 10 2 l 10 2 l 10 2 l 12 1 l 12 2 l 12 1 l 13 2 l 12 0 l 11 1 l 22 0 l 10 -1 l 10 -1 l 10 -2 l 11 -2 l 11 -2 l 22 -6 l 10 -3 l 10 -3 l 10 -3 l 10 -3 l 11 -3 l 11 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -3 l 12 -4 l 10 -3 l 11 -3 l 10 -4 l 11 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -4 l 13 -3 l 12 -3 l 11 -3 l 12 -2 l 11 -3 l 13 -2 l 13 -2 l 14 -2 l 15 -2 l 15 -2 l 14 -2 l 14 -1 l 13 -2 l 12 -1 l 13 -1 l 12 -2 l 14 -2 l 14 -2 l 14 -2 l 14 -2 l 14 -3 l 14 -4 l 14 -3 l 13 -4 l 22 -8 l 13 -4 l 13 -5 l 13 -6 l 14 -5 l 13 -6 l 13 -6 l 13 -6 l 13 -5 l 11 -6 l 12 -5 l 13 -6 l 13 -6 l 14 -6 l 14 -6 l 14 -6 l 14 -6 l 13 -6 l 12 -5 l 12 -5 l 11 -5 l 11 -5 l 12 -4 l 11 -5 l 12 -5 l 12 -6 l 11 -5 l 11 -5 l 10 -5 l 9 -5 l 8 -4 l 10 -7 l 10 -7 l 9 -7 l 10 -8 l 9 -9 l 9 -9 l 8 -9 l 7 -9 l 6 -8 l 6 -9 l 7 -10 l 8 -12 l 9 -15 l 10 -15 l 8 -14 l 7 -10 l 3 -4 l 0 -1" /> +<path style="fill:rgb(82%,0%,0%);" d="M 2640 4897 l 3 5 l 4 5 l 5 5 l 4 5 l 5 4 l 5 4 l 12 6 l 7 3 l 7 2 l 7 2 l 7 1 l 7 1 l 16 2 l 7 1 l 7 1 l 7 0 l 6 1 l 7 1 l 7 1 l 6 0 l 5 1 l 5 -1 l 6 0 l 6 -1 l 7 -1 l 8 -2 l 8 -1 l 7 -2 l 8 -1 l 8 -2 l 10 -2 l 10 -2 l 9 -3 l 8 -2 l 8 -3 l 10 -4 l 9 -5 l 10 -5 l 16 -12 l 6 -5 l 6 -5 l 6 -6 l 6 -7 l 6 -6 l 5 -7 l 5 -7 l 6 -7 l 6 -8 l 6 -9 l 7 -10 l 6 -9 l 7 -8 l 6 -9 l 6 -9 l 7 -9 l 7 -8 l 6 -8 l 11 -11 l 4 -6 l 5 -5 l 4 -4 l 3 -5 l 3 -4 l 2 -5 l 1 -7 l 0 -14 l -2 -12 l -2 -7 l -2 -8 l -2 -7 l -3 -6 l -2 -5 l -2 -6 l -3 -6 l -3 -5 l -2 -6 l -6 -10 l -4 -6 l -3 -6 l -4 -6 l -8 -12 l -1 -2 l -2 -2 l -2 -2 l -4 -4 l -3 -1 l -4 -1 l -5 0 l -5 1 l -12 4 l -8 3 l -8 4 l -9 5 l -10 7 l -11 7 l -11 7 l -11 8 l -13 10 l -14 10 l -15 11 l -15 12 l -16 13 l -17 14 l -17 13 l -16 14 l -17 14 l -16 13 l -15 13 l -14 12 l -13 12 l -12 11 l -11 10 l -10 9 l -13 12 l -11 11 l -17 19 l -5 8 l -5 7 l -2 5 l -2 5 l 0 7 l 1 3 Z7" /> +<path d="M 2891 5190 l 2 1 l 9 3 l 13 4 l 13 5 l 10 3 l 9 3 l 8 3 l 9 3 l 10 3 l 9 3 l 9 3 l 9 2 l 8 2 l 9 2 l 10 1 l 9 1 l 9 2 l 8 1 l 8 0 l 8 1 l 8 1 l 8 0 l 8 1 l 7 0 l 7 1 l 68 0 l 4 -1 l 4 0 l 1 -1 l 1 0 l 0 -1 l 1 0 l 0 -1" /> +<path style="fill:rgb(100%,100%,100%);" d="M 2468 6609 l -6 -7 l -6 -7 l -8 -7 l -8 -7 l -8 -8 l -9 -7 l -8 -7 l -7 -6 l -8 -6 l -9 -7 l -9 -6 l -9 -7 l -10 -6 l -10 -6 l -9 -5 l -9 -4 l -10 -5 l -11 -4 l -11 -3 l -13 -4 l -12 -3 l -13 -3 l -12 -2 l -11 -2 l -10 -1 l -10 -1 l -10 -2 l -11 0 l -11 -1 l -12 -1 l -23 0 l -11 -1 l -10 1 l -23 0 l -13 1 l -13 0 l -14 1 l -13 1 l -14 2 l -13 1 l -13 2 l -12 2 l -10 1 l -11 2 l -11 2 l -11 2 l -12 2 l -13 3 l -12 3 l -13 3 l -26 6 l -12 3 l -13 4 l -11 2 l -12 4 l -13 3 l -13 3 l -28 8 l -15 5 l -15 4 l -15 5 l -14 4 l -15 5 l -14 5 l -13 4 l -13 5 l -15 6 l -16 6 l -16 6 l -16 6 l -16 7 l -17 8 l -15 7 l -15 7 l -14 6 l -12 6 l -11 6 l -10 6 l -14 8 l -12 8 l -11 8 l -11 9 l -8 8 l -7 7 l -6 7 l -5 6 l -6 8 l -5 9 l -4 10 l -3 10 l -2 10 l -1 10 l 0 16 l 1 10 l 2 10 l 2 10 l 2 11 l 2 9 l 3 10 l 6 18 l 4 10 l 5 10 l 5 10 l 6 10 l 5 9 l 7 8 l 6 7 l 8 8 l 9 8 l 10 8 l 10 7 l 11 7 l 11 6 l 11 6 l 9 4 l 10 5 l 10 4 l 12 4 l 12 4 l 12 4 l 12 4 l 12 3 l 12 3 l 12 3 l 12 2 l 13 2 l 13 2 l 15 2 l 15 1 l 16 2 l 15 1 l 15 1 l 14 1 l 15 1 l 11 0 l 13 1 l 13 0 l 13 1 l 28 0 l 14 1 l 27 0 l 12 1 l 12 0 l 11 1 l 26 0 l 14 1 l 13 0 l 14 1 l 14 0 l 12 1 l 12 0 l 12 1 l 32 0 l 11 1 l 101 0 l 9 -1 l 10 -1 l 10 -1 l 11 -2 l 22 -8 l 11 -5 l 11 -7 l 11 -7 l 11 -9 l 11 -10 l 11 -11 l 9 -12 l 10 -13 l 10 -14 l 10 -15 l 10 -17 l 11 -18 l 10 -19 l 10 -19 l 10 -19 l 10 -19 l 9 -18 l 8 -18 l 7 -16 l 6 -16 l 6 -14 l 5 -12 l 5 -16 l 4 -14 l 3 -13 l 2 -11 l 0 -20 l -1 -8 l -2 -7 l -2 -6 l -3 -5 l -3 -4 Z" /> +<path d="M 4102 4658 l -2 1 l -8 6 l -12 8 l -12 8 l -9 5 l -8 4 l -7 3 l -8 3 l -18 4 l -9 1 l -8 1 l -7 1 l -8 0 l -8 1 l -9 0 l -9 1 l -16 0 l -8 1 l -29 0 l -10 -1 l -9 -1 l -8 -1 l -9 -2 l -10 -2 l -22 -6 l -10 -3 l -10 -4 l -8 -3 l -9 -3 l -9 -4 l -10 -4 l -10 -4 l -9 -5 l -9 -5 l -9 -4 l -9 -6 l -9 -6 l -9 -6 l -10 -7 l -10 -7 l -9 -7 l -8 -6 l -8 -6 l -7 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -5 l -8 -5 l -8 -5 l -9 -5 l -9 -6 l -10 -5 l -11 -6 l -10 -5 l -10 -4 l -9 -5 l -10 -4 l -10 -5 l -11 -4 l -12 -4 l -12 -5 l -12 -4 l -12 -3 l -11 -3 l -10 -3 l -10 -2 l -11 -2 l -11 -2 l -12 -2 l -12 -2 l -12 -2 l -11 -1 l -11 -2 l -10 -1 l -10 -1 l -11 0 l -11 -1 l -11 -1 l -44 0 l -10 1 l -9 0 l -12 2 l -13 1 l -12 2 l -13 3 l -12 3 l -11 2 l -10 3 l -9 3 l -8 3 l -7 4 l -8 4 l -8 4 l -7 5 l -8 4 l -8 5 l -8 6 l -7 4 l -8 5 l -10 6 l -11 7 l -14 8 l -15 9 l -14 9 l -10 6 l -4 3 l -1 0" /> +<path d="M 2940 2986 l -1 -1 l -7 -4 l -12 -8 l -15 -10 l -14 -9 l -12 -7 l -10 -6 l -10 -4 l -10 -4 l -10 -3 l -12 -3 l -11 -3 l -12 -2 l -12 -2 l -11 -1 l -11 -1 l -10 0 l -12 -1 l -12 1 l -12 0 l -12 1 l -12 2 l -11 2 l -10 2 l -10 3 l -10 4 l -11 4 l -11 5 l -10 5 l -10 6 l -9 5 l -7 6 l -8 6 l -7 7 l -7 7 l -7 8 l -6 8 l -6 9 l -4 8 l -4 8 l -4 9 l -3 9 l -3 11 l -2 10 l -2 11 l -2 11 l -1 10 l -1 10 l 0 40 l 2 11 l 1 10 l 3 9 l 2 9 l 4 9 l 4 9 l 5 10 l 5 10 l 7 9 l 6 9 l 6 8 l 7 7 l 6 7 l 7 6 l 8 7 l 9 6 l 8 7 l 8 5 l 8 5 l 8 5 l 8 4 l 8 4 l 9 4 l 10 4 l 10 4 l 9 3 l 10 3 l 9 2 l 9 2 l 10 2 l 10 1 l 12 2 l 11 1 l 10 1 l 11 0 l 9 1 l 19 0 l 10 1 l 10 0 l 10 -1 l 19 0 l 9 -1 l 9 -1 l 9 0 l 9 -2 l 10 -1 l 18 -2 l 9 -2 l 7 -1 l 10 -2 l 9 -1 l 10 -2 l 9 -2 l 8 -1 l 8 0 l 7 -1 l 7 0 l 14 2 l 7 2 l 7 3 l 14 7 l 9 4 l 9 4 l 9 4 l 9 2 l 10 2 l 10 1 l 12 -1 l 11 0 l 10 -1 l 9 -2 l 8 -1 l 8 -2 l 7 -3 l 6 -3 l 5 -4 l 4 -5 l 3 -6 l 3 -8 l 2 -9 l 1 -10 l 0 -20 l -1 -10 l -1 -11 l -3 -11 l -3 -11 l -3 -10 l -4 -8 l -4 -7 l -6 -7 l -8 -8 l -9 -8 l -6 -5 l -1 -1" /> +<path style="fill:rgb(100%,100%,100%);" d="M 3309 2031 l 9 -14 l 10 -13 l 10 -12 l 11 -13 l 11 -12 l 11 -12 l 11 -12 l 12 -11 l 11 -10 l 12 -9 l 11 -9 l 12 -9 l 12 -9 l 14 -8 l 14 -9 l 15 -8 l 16 -8 l 17 -8 l 16 -6 l 17 -5 l 16 -4 l 15 -2 l 15 0 l 14 1 l 11 2 l 12 4 l 12 4 l 12 6 l 11 8 l 12 8 l 11 10 l 11 11 l 10 11 l 10 11 l 8 12 l 8 12 l 7 12 l 6 12 l 5 13 l 5 13 l 5 13 l 4 15 l 4 15 l 3 16 l 3 17 l 4 34 l 2 18 l 1 17 l 0 17 l 1 17 l 0 48 l -1 17 l 0 17 l -1 19 l -2 38 l -2 20 l -1 20 l -2 20 l -3 20 l -4 38 l -3 19 l -6 36 l -4 17 l -3 18 l -4 18 l -5 19 l -5 19 l -5 20 l -5 19 l -6 20 l -6 19 l -7 19 l -6 19 l -7 17 l -6 17 l -7 16 l -6 15 l -7 15 l -8 17 l -8 16 l -8 16 l -10 16 l -10 16 l -10 16 l -11 16 l -11 15 l -12 15 l -11 13 l -12 13 l -12 11 l -11 11 l -12 10 l -12 10 l -13 9 l -14 9 l -14 8 l -15 8 l -16 8 l -16 7 l -17 6 l -17 5 l -16 4 l -16 3 l -15 2 l -15 1 l -15 1 l -15 -1 l -15 -1 l -15 -3 l -16 -3 l -16 -5 l -16 -6 l -16 -6 l -15 -8 l -15 -8 l -14 -9 l -13 -9 l -12 -10 l -11 -11 l -10 -10 l -9 -12 l -9 -12 l -8 -13 l -8 -15 l -8 -15 l -7 -16 l -6 -16 l -6 -17 l -5 -16 l -4 -17 l -4 -15 l -3 -16 l -3 -14 l -2 -14 l -2 -14 l -1 -14 l -1 -15 l -1 -14 l 0 -31 l 1 -16 l 1 -16 l 2 -16 l 2 -16 l 3 -16 l 4 -15 l 3 -15 l 4 -16 l 4 -14 l 5 -14 l 5 -15 l 5 -16 l 7 -16 l 6 -18 l 7 -17 l 8 -18 l 7 -19 l 8 -18 l 8 -17 l 8 -18 l 8 -17 l 8 -16 l 8 -16 l 8 -15 l 8 -15 l 8 -16 l 8 -15 l 8 -16 l 9 -16 l 9 -16 l 10 -16 l 9 -16 l 9 -16 l 10 -15 l 9 -14 l 8 -14 l 9 -12 l 8 -12 l 7 -12 Z" /> +<path style="stroke-width:45;" d="M 2498 3459 l 19 0 l 15 1 l 13 1 l 10 0 l 8 1 l 8 2 l 8 3 l 8 4 l 8 5 l 8 5 l 7 7 l 7 7 l 12 12 l 7 7 l 7 8 l 8 8 l 7 8 l 7 8 l 14 14 l 7 8 l 7 8 l 8 8 l 7 8 l 8 7 l 7 7 l 7 7 l 7 7 l 7 7 l 8 7 l 9 8 l 8 7 l 8 8 l 8 7 l 7 8 l 32 32 l 9 9 l 8 9 l 9 8 l 9 7 l 7 6 l 8 6 l 9 7 l 9 6 l 10 7 l 9 6 l 10 6 l 10 6 l 9 6 l 10 5 l 9 5 l 10 6 l 10 5 l 11 6 l 11 6 l 11 5 l 12 5 l 11 5 l 10 4 l 11 4 l 10 4 l 11 3 l 12 3 l 12 3 l 13 3 l 13 3 l 14 2 l 13 2 l 12 2 l 13 2 l 10 1 l 12 1 l 11 1 l 13 0 l 13 1 l 13 0 l 13 1 l 37 0 l 11 -1 l 11 0 l 13 -1 l 13 -1 l 13 -2 l 14 -1 l 14 -3 l 14 -2 l 13 -3 l 13 -3 l 12 -4 l 12 -3 l 12 -5 l 12 -4 l 13 -5 l 13 -6 l 14 -6 l 13 -6 l 13 -7 l 12 -5 l 12 -6 l 11 -5 l 11 -6 l 11 -5 l 11 -6 l 12 -5 l 12 -6 l 11 -6 l 12 -6 l 11 -6 l 11 -6 l 11 -6 l 11 -6 l 12 -7 l 12 -7 l 12 -7 l 12 -8 l 13 -8 l 11 -8 l 10 -7 l 10 -6 l 8 -7 l 9 -7 l 9 -8 l 8 -8 l 8 -7 l 7 -6 l 8 -6 l 7 -5 l 7 -4 l 7 -3 l 8 -2 l 10 -3 l 10 -1 l 9 -1 l 10 -1 l 8 -1 l 17 0 l 9 -1 l 29 0" /> +<path style="fill:rgb(100%,100%,100%);" d="M 2870 2736 l 6 -9 l 6 -8 l 6 -9 l 7 -9 l 6 -11 l 6 -11 l 6 -12 l 6 -13 l 6 -14 l 6 -15 l 4 -13 l 5 -13 l 5 -14 l 5 -16 l 6 -17 l 6 -18 l 5 -19 l 12 -38 l 6 -18 l 6 -19 l 10 -34 l 5 -16 l 5 -16 l 5 -15 l 5 -16 l 10 -32 l 5 -16 l 5 -16 l 5 -15 l 5 -15 l 5 -14 l 5 -13 l 4 -12 l 8 -22 l 5 -13 l 5 -12 l 5 -12 l 4 -12 l 5 -12 l 5 -13 l 5 -12 l 5 -11 l 5 -11 l 4 -10 l 4 -10 l 4 -9 l 4 -12 l 5 -11 l 4 -12 l 5 -13 l 5 -12 l 4 -12 l 4 -11 l 4 -11 l 6 -18 l 3 -10 l 3 -10 l 3 -10 l 2 -20 l -1 -10 l -1 -10 l -3 -10 l -3 -8 l -3 -7 l -4 -8 l -5 -9 l -6 -8 l -6 -8 l -8 -8 l -8 -7 l -8 -6 l -9 -5 l -9 -3 l -9 -2 l -10 -2 l -11 0 l -11 2 l -13 2 l -13 3 l -13 4 l -13 5 l -13 6 l -12 5 l -11 6 l -11 5 l -9 6 l -11 7 l -11 7 l -10 7 l -10 8 l -10 9 l -10 10 l -10 10 l -10 11 l -10 11 l -10 13 l -8 9 l -8 10 l -9 12 l -9 12 l -10 13 l -11 15 l -11 14 l -10 16 l -11 15 l -11 16 l -10 15 l -10 15 l -9 15 l -9 15 l -9 15 l -9 15 l -9 16 l -9 16 l -9 16 l -9 17 l -8 17 l -8 16 l -8 16 l -7 14 l -7 14 l -6 13 l -6 12 l -5 11 l -6 12 l -5 12 l -5 11 l -4 11 l -5 12 l -4 12 l -4 11 l -3 12 l -3 13 l -3 12 l -3 13 l -2 14 l -2 12 l -2 14 l -2 14 l -1 16 l -2 17 l -1 18 l -1 17 l -1 18 l -1 18 l 0 17 l 1 16 l 0 15 l 1 14 l 2 14 l 3 17 l 4 16 l 5 15 l 6 14 l 6 14 l 7 12 l 7 11 l 7 9 l 7 8 l 7 7 l 8 7 l 8 7 l 9 7 l 9 5 l 10 5 l 9 4 l 10 3 l 9 2 l 10 2 l 24 0 l 13 -1 l 14 -3 l 13 -3 l 12 -6 l 11 -6 l 9 -6 l 10 -7 l 9 -9 l 10 -9 l 9 -10 l 9 -11 l 9 -10 l 8 -10 l 7 -10 Z" /> +<path d="M 3489 1649 l 1 0 l 4 -3 l 10 -6 l 16 -8 l 19 -10 l 20 -11 l 19 -10 l 18 -8 l 16 -7 l 14 -5 l 13 -4 l 13 -4 l 13 -2 l 13 -2 l 14 -1 l 29 0 l 15 1 l 30 4 l 14 3 l 13 4 l 12 4 l 12 4 l 12 5 l 11 6 l 12 6 l 11 7 l 12 9 l 11 9 l 11 10 l 10 10 l 10 11 l 8 11 l 8 12 l 7 12 l 6 11 l 6 12 l 5 14 l 5 15 l 6 17 l 6 20 l 6 22 l 6 23 l 6 22 l 6 21 l 4 15 l 2 9 l 1 4 l 0 1" /> +<path d="M 3278 1680 l 0 -1 l -1 -5 l -3 -10 l -4 -14 l -5 -16 l -5 -14 l -4 -13 l -10 -18 l -5 -6 l -7 -7 l -7 -5 l -8 -5 l -10 -5 l -10 -4 l -11 -4 l -11 -3 l -12 -2 l -11 -2 l -11 -1 l -11 -1 l -12 -1 l -13 0 l -14 1 l -14 1 l -15 2 l -14 3 l -13 4 l -13 4 l -13 5 l -20 12 l -11 7 l -11 8 l -12 9 l -12 10 l -12 11 l -13 11 l -12 12 l -12 11 l -11 12 l -12 12 l -9 10 l -10 9 l -10 11 l -10 11 l -11 11 l -11 12 l -11 13 l -12 13 l -11 14 l -12 13 l -11 14 l -11 14 l -10 13 l -10 13 l -10 13 l -9 14 l -9 13 l -9 14 l -9 14 l -9 15 l -9 16 l -9 16 l -9 16 l -9 17 l -9 17 l -8 16 l -8 16 l -7 16 l -7 15 l -6 15 l -6 14 l -6 13 l -6 15 l -6 16 l -6 15 l -5 16 l -12 32 l -5 16 l -5 15 l -5 16 l -5 14 l -4 14 l -5 13 l -4 12 l -4 12 l -5 13 l -4 14 l -6 14 l -5 14 l -5 14 l -6 15 l -6 14 l -5 14 l -6 14 l -5 13 l -5 13 l -5 13 l -4 13 l -5 14 l -6 15 l -6 17 l -7 19 l -7 22 l -8 23 l -7 22 l -6 17 l -4 12 l -2 5 l 0 1" /> +<path style="fill:rgb(100%,84%,0%);" d="M 4036 5613 l 12 8 l 12 8 l 11 8 l 12 7 l 12 8 l 11 7 l 11 7 l 11 7 l 10 6 l 9 6 l 10 6 l 8 5 l 22 14 l 11 7 l 12 7 l 11 8 l 12 7 l 12 8 l 10 7 l 10 6 l 10 7 l 9 6 l 10 6 l 10 6 l 10 7 l 9 6 l 10 7 l 9 5 l 8 6 l 7 4 l 6 4 l 10 7 l 9 5 l 9 5 l 8 4 l 7 3 l 6 2 l 7 1 l 14 0 l 7 -1 l 6 -2 l 5 -2 l 6 -2 l 5 -4 l 5 -3 l 4 -3 l 8 -8 l 3 -5 l 4 -5 l 4 -5 l 3 -5 l 8 -10 l 5 -6 l 3 -5 l 3 -5 l 4 -6 l 3 -7 l 2 -7 l 2 -7 l 1 -6 l 0 -13 l -1 -7 l -1 -8 l -1 -6 l -1 -6 l -2 -5 l -3 -5 l -3 -6 l -4 -5 l -9 -9 l -5 -4 l -5 -5 l -7 -5 l -7 -5 l -7 -5 l -7 -5 l -7 -5 l -8 -5 l -9 -6 l -20 -12 l -9 -6 l -8 -5 l -9 -5 l -9 -6 l -11 -7 l -10 -7 l -10 -6 l -10 -7 l -9 -6 l -10 -6 l -9 -6 l -10 -7 l -11 -6 l -9 -6 l -9 -6 l -8 -5 l -8 -4 l -6 -4 l -7 -4 l -7 -4 l -7 -4 l -14 -8 l -7 -4 l -7 -5 l -8 -6 l -9 -6 l -9 -6 l -10 -8 l -9 -7 l -9 -6 l -7 -5 l -6 -5 l -5 -3 l -4 -3 l -3 -2 l -4 -1 l -14 0 l -6 1 l -7 1 l -8 1 l -9 2 l -10 1 l -12 2 l -12 2 l -13 2 l -12 1 l -12 2 l -12 2 l -12 2 l -12 2 l -12 1 l -13 2 l -12 3 l -12 2 l -10 2 l -10 1 l -8 2 l -7 2 l -3 1 l -2 0 l -6 3 l -2 0 l -1 1 l -2 1 l -2 2 l 0 2 l -1 1 l 0 4 l 4 8 l 2 2 l 4 4 l 2 3 l 3 2 l 6 6 l 7 6 l 10 7 l 10 9 l 12 9 l 13 10 l 15 10 l 14 11 l 15 10 l 14 10 l 14 10 l 13 9 Z" /> +<path style="fill:rgb(82%,0%,0%);" d="M 2303 4762 l 6 8 l 7 7 l 7 7 l 7 8 l 7 7 l 7 6 l 6 6 l 6 5 l 8 7 l 8 7 l 9 7 l 9 6 l 9 5 l 9 4 l 7 2 l 8 3 l 9 2 l 9 2 l 10 2 l 10 1 l 10 2 l 9 1 l 9 0 l 11 1 l 10 1 l 44 0 l 9 -1 l 9 -1 l 10 -1 l 10 -1 l 10 -2 l 11 -2 l 20 -4 l 9 -2 l 9 -2 l 10 -3 l 11 -2 l 10 -3 l 11 -3 l 10 -3 l 9 -3 l 8 -3 l 8 -2 l 8 -4 l 8 -3 l 7 -4 l 8 -4 l 7 -4 l 7 -5 l 12 -10 l 7 -6 l 7 -7 l 8 -7 l 8 -8 l 8 -9 l 7 -8 l 8 -8 l 6 -7 l 14 -14 l 7 -8 l 8 -9 l 7 -8 l 8 -8 l 7 -8 l 6 -8 l 7 -7 l 7 -9 l 16 -18 l 8 -10 l 8 -9 l 6 -9 l 7 -8 l 5 -7 l 5 -8 l 5 -7 l 4 -8 l 5 -8 l 3 -8 l 3 -7 l 3 -7 l 1 -7 l 2 -7 l 0 -8 l 1 -8 l 0 -17 l -1 -9 l 0 -8 l -2 -16 l -1 -9 l -2 -9 l -2 -9 l -2 -10 l -3 -9 l -3 -8 l -4 -7 l -5 -8 l -5 -7 l -6 -7 l -7 -8 l -7 -6 l -8 -7 l -7 -6 l -6 -5 l -7 -5 l -7 -4 l -8 -5 l -8 -5 l -8 -4 l -7 -4 l -8 -4 l -7 -3 l -7 -4 l -16 -6 l -9 -3 l -9 -2 l -8 -3 l -8 -2 l -16 -2 l -8 -1 l -9 -1 l -26 0 l -8 1 l -8 1 l -10 1 l -10 2 l -10 2 l -11 4 l -9 3 l -8 4 l -4 3 l -5 3 l -6 5 l -7 6 l -9 7 l -10 9 l -12 11 l -14 13 l -16 14 l -18 17 l -11 10 l -12 11 l -14 12 l -14 13 l -15 14 l -16 15 l -16 15 l -17 16 l -17 16 l -17 16 l -16 17 l -16 15 l -14 15 l -14 15 l -13 13 l -11 13 l -11 12 l -9 11 l -8 12 l -8 10 l -6 11 l -5 9 l -4 10 l -3 8 l -1 8 l -1 8 l 0 7 l 1 6 l 2 6 l 2 5 l 3 4 l 3 5 l 3 4 Z" /> +<path style="fill:rgb(100%,100%,100%);" d="M 2288 6848 l 4 -11 l 6 -10 l 7 -12 l 8 -11 l 9 -11 l 10 -10 l 10 -10 l 9 -9 l 9 -7 l 9 -7 l 9 -7 l 8 -5 l 9 -6 l 8 -6 l 10 -5 l 9 -5 l 8 -5 l 9 -4 l 9 -4 l 8 -4 l 9 -5 l 9 -5 l 10 -5 l 11 -5 l 11 -5 l 12 -6 l 11 -5 l 11 -5 l 10 -5 l 10 -4 l 10 -4 l 10 -4 l 11 -4 l 11 -4 l 12 -4 l 12 -3 l 11 -4 l 11 -3 l 11 -3 l 11 -2 l 11 -3 l 11 -3 l 13 -2 l 13 -3 l 13 -2 l 13 -3 l 13 -2 l 13 -2 l 12 -2 l 12 -1 l 11 -2 l 12 -1 l 12 -2 l 13 -1 l 13 -1 l 13 -1 l 12 0 l 12 -1 l 22 0 l 11 -1 l 11 1 l 24 0 l 12 1 l 13 1 l 12 1 l 11 1 l 12 1 l 11 2 l 10 1 l 12 2 l 12 2 l 12 3 l 13 2 l 12 3 l 12 3 l 12 2 l 10 3 l 10 3 l 12 4 l 12 3 l 12 5 l 13 4 l 12 5 l 11 5 l 10 5 l 10 6 l 10 5 l 10 6 l 10 7 l 11 8 l 11 8 l 10 8 l 9 8 l 9 9 l 7 6 l 7 7 l 7 8 l 7 8 l 7 8 l 7 9 l 7 8 l 6 9 l 5 8 l 5 8 l 6 9 l 5 11 l 5 12 l 5 12 l 5 12 l 4 12 l 3 12 l 4 11 l 2 9 l 4 20 l 2 11 l 2 11 l 2 10 l 1 11 l 2 9 l 1 10 l 1 8 l 0 15 l -1 5 l -1 6 l -2 5 l -2 5 l -4 6 l -10 10 l -7 6 l -8 5 l -9 5 l -11 4 l -11 5 l -13 5 l -12 4 l -13 4 l -14 4 l -32 8 l -19 4 l -20 4 l -21 3 l -22 4 l -23 3 l -25 3 l -24 3 l -52 4 l -25 1 l -26 0 l -26 1 l -78 -3 l -24 -2 l -50 -6 l -26 -3 l -26 -4 l -27 -4 l -27 -5 l -56 -12 l -28 -6 l -28 -6 l -27 -7 l -26 -7 l -25 -7 l -25 -7 l -23 -7 l -22 -7 l -20 -7 l -19 -7 l -18 -7 l -16 -6 l -15 -7 l -17 -7 l -15 -8 l -14 -8 l -13 -8 l -11 -8 l -10 -8 l -9 -8 l -7 -8 l -6 -8 l -5 -8 l -3 -8 l -3 -8 l -1 -7 l -1 -7 l 0 -7 l 1 -6 l 2 -7 Z" /> +<path style="fill:rgb(82%,0%,0%);" d="M 2232 4239 l -8 3 l -8 5 l -9 4 l -9 5 l -8 5 l -7 6 l -7 5 l -7 6 l -7 8 l -8 8 l -7 9 l -7 10 l -5 7 l -5 9 l -5 9 l -6 11 l -5 10 l -4 10 l -4 10 l -2 8 l -3 9 l -2 9 l -1 9 l -2 18 l 0 17 l -1 9 l 0 47 l 1 9 l 0 9 l 2 9 l 1 8 l 3 8 l 3 9 l 4 9 l 5 9 l 5 8 l 6 8 l 6 8 l 7 7 l 9 8 l 9 8 l 10 8 l 10 8 l 10 7 l 10 6 l 8 5 l 9 5 l 9 4 l 9 3 l 9 3 l 10 3 l 10 2 l 9 1 l 10 2 l 10 1 l 11 1 l 12 2 l 26 2 l 13 1 l 11 0 l 11 1 l 11 1 l 46 0 l 12 -2 l 10 -1 l 11 -2 l 18 -6 l 9 -3 l 10 -4 l 10 -5 l 11 -5 l 9 -5 l 10 -5 l 8 -6 l 9 -5 l 10 -7 l 20 -16 l 10 -9 l 9 -9 l 8 -9 l 6 -8 l 6 -8 l 5 -8 l 4 -7 l 4 -8 l 3 -9 l 3 -8 l 2 -7 l 1 -7 l 2 -7 l 1 -8 l 2 -10 l 1 -10 l 0 -22 l -1 -11 l -2 -9 l -2 -10 l -2 -11 l -3 -11 l -3 -12 l -4 -11 l -4 -10 l -3 -9 l -4 -9 l -5 -8 l -5 -9 l -6 -8 l -6 -8 l -7 -7 l -6 -7 l -7 -6 l -7 -5 l -6 -5 l -8 -5 l -9 -5 l -10 -5 l -11 -5 l -12 -5 l -12 -5 l -13 -4 l -13 -5 l -12 -3 l -13 -4 l -14 -3 l -15 -3 l -16 -4 l -16 -3 l -16 -3 l -16 -2 l -28 -4 l -12 -1 l -11 -1 l -15 -1 l -13 0 l -12 1 l -11 2 l -10 2 l -8 3 l -7 3 Z" /> +<path style="fill:rgb(82%,0%,0%);" d="M 2246 4048 l 1 -8 l 1 -10 l 3 -10 l 3 -11 l 5 -10 l 4 -10 l 5 -6 l 4 -7 l 6 -7 l 6 -6 l 7 -6 l 7 -6 l 6 -5 l 7 -5 l 6 -4 l 7 -5 l 7 -4 l 8 -4 l 7 -4 l 8 -4 l 8 -3 l 7 -2 l 8 -3 l 8 -2 l 9 -3 l 10 -2 l 9 -2 l 10 -1 l 8 -2 l 9 0 l 16 -2 l 9 0 l 9 -1 l 25 0 l 8 -1 l 20 0 l 11 -1 l 38 0 l 9 1 l 9 1 l 10 2 l 8 2 l 8 2 l 8 2 l 9 4 l 9 4 l 9 4 l 10 6 l 9 6 l 7 4 l 7 6 l 9 6 l 8 7 l 8 7 l 8 7 l 6 7 l 6 6 l 5 6 l 5 7 l 4 8 l 4 7 l 3 8 l 3 8 l 4 14 l 2 7 l 2 8 l 2 9 l 1 9 l 2 10 l 1 9 l 1 10 l 0 10 l 1 10 l 0 10 l -1 12 l -1 12 l -1 12 l -2 12 l -3 11 l -3 9 l -8 18 l -6 9 l -7 8 l -8 8 l -8 7 l -8 7 l -9 5 l -7 4 l -8 4 l -9 4 l -10 3 l -10 4 l -10 3 l -11 3 l -10 2 l -11 2 l -10 2 l -10 1 l -11 1 l -12 1 l -13 1 l -13 1 l -13 1 l -48 0 l -11 -1 l -11 0 l -12 -1 l -11 -1 l -12 -2 l -12 -2 l -11 -2 l -10 -2 l -10 -3 l -9 -3 l -10 -5 l -11 -5 l -11 -6 l -10 -8 l -10 -8 l -9 -8 l -8 -8 l -8 -8 l -7 -8 l -7 -9 l -6 -10 l -7 -10 l -6 -10 l -5 -10 l -4 -9 l -3 -8 l -4 -10 l -3 -10 l -2 -10 l -1 -9 l -1 -8 l -1 -7 l -1 -6 l -2 -14 Z" /> +<path d="M 1481 6669 l 1 1 l 5 3 l 12 7 l 17 10 l 18 10 l 17 10 l 16 9 l 13 7 l 13 6 l 12 5 l 10 4 l 22 8 l 12 3 l 12 4 l 13 3 l 13 3 l 13 3 l 13 2 l 12 3 l 12 1 l 12 2 l 13 2 l 12 1 l 14 2 l 14 1 l 15 1 l 16 1 l 15 1 l 16 1 l 15 0 l 15 1 l 93 0 l 15 -1 l 30 0 l 15 -1 l 15 0 l 30 -2 l 15 0 l 14 -1 l 17 0 l 18 -1 l 38 -2 l 19 0 l 19 -1 l 18 -1 l 17 -1 l 15 0 l 13 -1 l 11 0 l 9 -1 l 16 0 l 1 -1 l 3 0 l -1 1 l -7 0" /> +<path d="M 3533 6267 l 0 1 l 1 7 l 1 14 l 1 16 l 1 15 l 1 11 l 0 18 l -2 10 l -1 9 l -3 9 l -3 8 l -4 7 l -3 6 l -5 6 l -5 6 l -6 7 l -6 6 l -7 5 l -7 5 l -6 3 l -6 4 l -8 3 l -8 4 l -10 3 l -9 3 l -10 3 l -10 3 l -9 2 l -10 2 l -10 3 l -13 3 l -13 3 l -14 4 l -15 4 l -16 5 l -15 4 l -17 6 l -12 4 l -14 5 l -15 5 l -17 7 l -19 7 l -22 8 l -24 10 l -25 10 l -25 9 l -23 9 l -16 7 l -11 4 l -4 2 l -1 0" /> +<path d="M 3983 6181 l 0 5 l 1 10 l 2 15 l 1 19 l 2 20 l 2 18 l 1 16 l 1 15 l 1 12 l 1 11 l 1 11 l 1 12 l 0 12 l 1 12 l 0 44 l -1 10 l 0 8 l -1 8 l -2 9 l -3 9 l -3 8 l -4 9 l -5 7 l -5 7 l -6 6 l -6 5 l -7 4 l -8 4 l -10 4 l -10 5 l -12 4 l -12 3 l -11 4 l -12 4 l -11 2 l -10 4 l -12 3 l -13 4 l -13 3 l -14 4 l -14 4 l -14 3 l -13 3 l -13 3 l -11 2 l -12 3 l -12 2 l -14 2 l -14 3 l -15 3 l -15 4 l -15 3 l -16 4 l -15 5 l -16 4 l -16 5 l -12 5 l -13 4 l -14 5 l -15 6 l -17 7 l -18 8 l -21 9 l -23 10 l -23 10 l -23 11 l -22 9 l -18 8 l -13 6 l -7 3 l -4 2" /> +<path style="fill:rgb(100%,100%,100%);" d="M 2263 6883 l -3 7 l -4 18 l -2 8 l 0 9 l -1 8 l 0 9 l -1 9 l 0 21 l 1 10 l 0 9 l 1 9 l 0 9 l 2 9 l 1 9 l 2 9 l 3 8 l 2 5 l 3 6 l 4 7 l 6 7 l 7 7 l 8 8 l 9 7 l 11 8 l 8 5 l 10 5 l 10 6 l 12 7 l 12 6 l 14 7 l 14 7 l 14 6 l 14 7 l 13 5 l 13 6 l 13 5 l 13 4 l 13 4 l 13 5 l 14 4 l 15 4 l 15 3 l 16 4 l 32 6 l 16 3 l 17 2 l 16 2 l 15 2 l 15 1 l 17 2 l 17 2 l 18 1 l 20 2 l 19 1 l 20 2 l 38 2 l 19 2 l 34 2 l 16 1 l 16 0 l 16 1 l 16 1 l 16 1 l 17 1 l 17 1 l 17 0 l 18 1 l 17 1 l 17 1 l 17 0 l 17 1 l 16 1 l 17 1 l 14 0 l 16 1 l 15 0 l 17 1 l 18 1 l 18 0 l 18 1 l 19 0 l 18 1 l 19 0 l 18 1 l 97 0 l 17 -1 l 17 0 l 17 -1 l 17 -1 l 18 -1 l 18 -1 l 18 -2 l 18 -1 l 18 -2 l 17 -1 l 17 -2 l 17 -2 l 17 -2 l 30 -4 l 16 -2 l 17 -2 l 18 -2 l 18 -2 l 19 -3 l 19 -2 l 18 -3 l 18 -3 l 18 -2 l 17 -3 l 17 -2 l 15 -3 l 15 -2 l 14 -2 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 14 -3 l 14 -3 l 14 -4 l 14 -3 l 12 -4 l 13 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -3 l 12 -5 l 13 -4 l 14 -5 l 28 -10 l 15 -5 l 14 -6 l 15 -5 l 14 -6 l 14 -5 l 13 -6 l 14 -5 l 13 -6 l 14 -5 l 15 -7 l 15 -6 l 15 -7 l 16 -6 l 16 -7 l 16 -7 l 16 -7 l 14 -6 l 15 -7 l 13 -6 l 13 -5 l 12 -5 l 13 -6 l 13 -6 l 13 -6 l 13 -6 l 13 -6 l 12 -5 l 11 -5 l 11 -5 l 9 -5 l 9 -4 l 8 -3 l 7 -3 l 12 -6 l 10 -6 l 10 -5 l 8 -5 l 6 -5 l 5 -5 l 4 -5 l 5 -7 l 4 -7 l 3 -7 l 3 -7 l 2 -7 l 1 -6 l 1 -7 l 0 -7 l 1 -7 l -1 -7 l 0 -6 l -1 -6 l 0 -7 l -2 -14 l 0 -7 l -1 -6 l 0 -7 l -1 -7 l 0 -8 l -1 -9 l 0 -8 l -1 -9 l -1 -5 l 0 -6 l -2 -6 l -2 -5 l -2 -6 l -3 -5 l -8 -6 l -5 -2 l -13 0 l -8 2 l -10 4 l -11 4 l -12 6 l -14 6 l -14 7 l -14 8 l -14 7 l -14 8 l -13 6 l -13 7 l -14 7 l -15 7 l -16 7 l -16 8 l -16 7 l -15 8 l -16 6 l -14 7 l -14 6 l -12 5 l -13 5 l -13 5 l -13 5 l -13 5 l -13 5 l -14 5 l -13 4 l -14 4 l -12 5 l -13 4 l -12 3 l -12 4 l -11 3 l -11 3 l -12 4 l -12 3 l -13 4 l -14 4 l -14 4 l -15 3 l -15 4 l -15 4 l -14 3 l -15 4 l -14 3 l -15 4 l -15 3 l -16 3 l -16 3 l -17 4 l -18 3 l -19 4 l -19 3 l -19 4 l -19 3 l -19 3 l -17 2 l -17 3 l -17 2 l -15 3 l -16 1 l -32 4 l -16 2 l -16 2 l -17 1 l -17 2 l -17 1 l -16 1 l -16 1 l -16 1 l -14 1 l -15 1 l -14 1 l -14 1 l -15 1 l -15 0 l -16 1 l -17 1 l -18 1 l -18 0 l -38 2 l -19 1 l -19 0 l -19 1 l -19 0 l -19 1 l -16 0 l -16 1 l -17 0 l -18 1 l -19 0 l -19 1 l -20 0 l -20 1 l -63 0 l -20 1 l -112 0 l -19 -1 l -19 0 l -19 -1 l -20 0 l -20 -1 l -19 -1 l -20 -1 l -19 -1 l -19 -1 l -18 -1 l -17 -2 l -17 -1 l -15 -1 l -14 -2 l -14 -1 l -12 -1 l -17 -3 l -16 -2 l -15 -2 l -15 -2 l -15 -3 l -15 -3 l -14 -3 l -13 -3 l -12 -3 l -11 -2 l -10 -3 l -10 -3 l -11 -3 l -12 -4 l -12 -4 l -11 -4 l -12 -4 l -11 -4 l -20 -8 l -8 -4 l -7 -4 l -9 -5 l -9 -5 l -8 -6 l -8 -5 l -8 -6 l -7 -5 l -6 -5 l -5 -5 l -8 -6 l -8 -6 l -8 -6 l -8 -5 l -7 -5 l -5 -4 l -4 -3 l -4 -3 l -4 -2 l -3 -2 l -4 -1 l -3 0 l -3 1 l -3 2 l -5 4 l -5 6 l -6 8 l -5 9 Z" /> +<path style="fill:rgb(100%,100%,100%);stroke-width:15;" d="M 4281 6302 l 7 -6 l 9 -5 l 8 -4 l 9 -4 l 8 -2 l 8 -1 l 7 -1 l 7 0 l 8 1 l 7 2 l 7 2 l 7 3 l 7 3 l 7 4 l 7 6 l 14 12 l 6 7 l 6 7 l 6 8 l 6 9 l 5 10 l 4 10 l 3 10 l 1 7 l 1 8 l 1 9 l 0 10 l -1 10 l -2 18 l -1 9 l -2 8 l -2 9 l -3 9 l -3 9 l -3 10 l -8 16 l -4 8 l -5 6 l -5 7 l -7 7 l -6 7 l -8 6 l -7 5 l -7 3 l -7 4 l -9 2 l -11 2 l -10 0 l -11 -1 l -10 -2 l -9 -2 l -9 -3 l -9 -4 l -9 -5 l -8 -4 l -8 -5 l -6 -5 l -7 -5 l -5 -5 l -6 -5 l -5 -6 l -4 -6 l -3 -5 l -3 -7 l -3 -6 l -2 -8 l -1 -8 l -1 -8 l 0 -8 l -1 -8 l 1 -9 l 0 -9 l 1 -10 l 2 -9 l 1 -7 l 2 -8 l 1 -8 l 6 -16 l 4 -9 l 4 -7 l 4 -7 l 4 -6 l 5 -8 l 6 -7 l 6 -7 l 6 -7 l 6 -6 Z" /> +<g style="stroke:rgb(0%,100%,100%);"> +<path d="M 3248 6546 l 6 0 l 11 1 l 15 1 l 16 2 l 16 2 l 14 1 l 12 2 l 11 2 l 10 3 l 10 2 l 11 4 l 12 4 l 14 6 l 16 6 l 16 7 l 15 7 l 11 4 l 5 3 l 1 0" /> +<path d="M 3095 6246 l 14 0 l 14 1 l 18 1 l 18 0 l 18 1 l 16 2 l 14 1 l 13 1 l 12 2 l 12 2 l 12 3 l 13 3 l 14 3 l 16 5 l 18 5 l 20 6 l 21 7 l 20 6 l 16 6 l 11 3 l 4 2 l 1 0" /> +<path d="M 3599 6276 l 1 0 l 5 1 l 11 1 l 17 1 l 21 2 l 22 2 l 21 2 l 20 2 l 17 2 l 15 2 l 14 2 l 14 2 l 14 2 l 14 3 l 16 2 l 17 4 l 20 3 l 21 5 l 23 4 l 22 5 l 18 3 l 11 3 l 5 1 l 1 0" /> +<path d="M 3440 6504 l 45 0 l 15 1 l 13 0 l 12 1 l 10 1 l 10 1 l 10 2 l 10 2 l 12 3 l 13 3 l 16 5 l 16 5 l 15 4 l 10 3 l 5 2 l 1 0" /> +<path d="M 3560 6402 l 1 0 l 5 1 l 12 1 l 19 1 l 23 2 l 24 2 l 22 2 l 20 2 l 18 2 l 16 2 l 14 2 l 13 2 l 13 2 l 14 2 l 13 3 l 32 6 l 19 5 l 19 4 l 18 4 l 15 4 l 9 2 l 4 1 l 1 0" /> +<path d="M 2861 6429 l 2 0 l 3 1 l 6 1 l 9 1 l 6 1 l 7 1 l 8 1 l 10 2 l 11 2 l 12 3 l 12 2 l 12 3 l 12 3 l 12 4 l 10 3 l 11 3 l 12 4 l 13 5 l 15 5 l 16 6 l 18 7 l 17 6 l 14 6 l 8 3 l 4 2 l 1 0" /> +<path d="M 2594 6492 l 6 0 l 11 1 l 17 0 l 21 1 l 22 1 l 21 2 l 20 1 l 17 1 l 16 2 l 14 1 l 15 2 l 12 2 l 13 2 l 14 3 l 15 3 l 17 3 l 19 4 l 20 5 l 22 5 l 21 5 l 18 4 l 14 3 l 9 2 l 3 1 l 1 0" /> +<path d="M 3023 6360 l 1 0 l 4 1 l 9 1 l 15 3 l 18 3 l 19 3 l 18 3 l 16 3 l 15 3 l 13 3 l 12 2 l 12 3 l 12 3 l 26 8 l 15 4 l 18 6 l 19 6 l 20 6 l 19 7 l 16 5 l 10 3 l 4 2 l 1 0" /> +</g> +</g> +<g style="stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;stroke-linecap:butt;stroke-linejoin:miter;fill-rule:nonzero;fill-opacity:1;stroke-width:7.5;"> +<path style="fill:rgb(0%,0%,0%);" d="M 126 31 C 94 159 12 248 -58 231 C -127 214 -158 96 -126 -32 C -94 -159 -12 -248 58 -231 C 127 -214 158 -96 126 31" transform="matrix(0.035,0,0,0.035,96.18,89.005)"/> +<path style="fill:rgb(0%,0%,0%);" d="M 174 43 C 136 193 28 295 -68 271 C -163 247 -211 106 -174 -43 C -136 -193 -28 -295 67 -271 C 163 -247 211 -106 174 43" transform="matrix(0.035,0,0,0.035,115.185,93.205)"/> +<path style="fill:rgb(100%,100%,100%);" d="M 54 10 C 30 147 -79 128 -54 -10 C -30 -147 79 -128 54 10" transform="matrix(0.035,0,0,0.035,114.1,91.105)"/> +<path style="fill:rgb(100%,100%,100%);" d="M 54 10 C 30 147 -79 128 -54 -10 C -30 -147 79 -128 54 10" transform="matrix(0.035,0,0,0.035,95.83,87.325)"/> +</g> +</svg> diff --git a/share/examples/BSD_daemon/beastie2.eps b/share/examples/BSD_daemon/beastie2.eps new file mode 100644 index 000000000000..05761bf5b9b3 --- /dev/null +++ b/share/examples/BSD_daemon/beastie2.eps @@ -0,0 +1,2470 @@ +%!PS-Adobe-2.0 EPSF-1.2 +%%Title: beastie1.ps +%%Creator: Sketch 0.6.12 +%%CreationDate: Sun May 26 00:37:36 2002 +%%For: Rahul Siddharthan +%%Pages: 1 +%%DocumentFonts: +%%BoundingBox: 385 514 545 694 +save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def +%%EndProlog +%%Page 1 1 + +/SketchDict 100 dict def +SketchDict begin +/bd { bind def } bind def +/x { exch } bd +/xd { exch def } bd +/PI 3.14159265358979323846264338327 def +/radgrad { 180 mul PI div } bd +/skstartmatrix matrix currentmatrix def +/tmpmat matrix def +/ISOLatin1Encoding dup where +{ pop pop } +{ [/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand +/quoteright /parenleft /parenright /asterisk /plus /comma /minus /period +/slash /zero /one /two /three /four /five /six /seven /eight /nine /colon +/semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J +/K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash +/bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i +/j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright +/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +/.notdef /.notdef /dotlessi /grave /acute /circumflex /tilde /macron /breve +/dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek +/caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section +/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen +/registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu +/paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright +/onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex +/Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex +/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve +/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute +/Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute +/acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute +/ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde +/ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave +/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def +} +ifelse +/arct dup where +{pop pop} +{ +/arct {arcto pop pop pop pop} bd +} +ifelse +/size 0 def +/fontname 0 def +/newfont 0 def +/sf { +/size xd +/fontname xd +fontname findfont +dup /Encoding get StandardEncoding eq +{ +dup +length dict /newfont xd +{ +1 index +/FID ne +{ newfont 3 1 roll put } +{ pop pop } +ifelse +} forall +newfont /Encoding ISOLatin1Encoding put +fontname newfont definefont +} +if +size scalefont setfont +} bd +/pusht {matrix currentmatrix} bd +/popt {setmatrix} bd +/pushc {gsave} bd +/popc {grestore} bd +/rgb {setrgbcolor} bd +/w { setlinewidth } bd +/j { setlinejoin } bd +/J { setlinecap } bd +/d { setdash } bd +/F { eofill } bd +/f { closepath F } bd +/S { +pusht +skstartmatrix setmatrix stroke +popt +} bd +/s { closepath S } bd +/m { moveto } bd +/l { lineto } bd +/c { curveto } bd +/txt { +/tmpmat tmpmat currentmatrix def +dup type /arraytype eq {concat} {translate} ifelse +0 0 m +tmpmat +} bd +/T {txt x show popt} bd +/P {txt x true charpath popt} bd +/TP {txt x dup show 0 0 m true charpath popt} bd +/C {newpath 0 360 arc} bd +/R { +2 copy m +x 2 index l +x 2 index x l +l +closepath +} bd +/ellipse { +dup type /arraytype eq +{ +pusht x concat +0 0 1.0 C +popt +} +{ +pusht 5 1 roll +4 -1 roll concat +newpath +dup 2 eq { +0 0 m +} if +3 1 roll +radgrad x +radgrad x +0 0 1 5 -2 roll +arc +0 ne { closepath } if +popt +} +ifelse +} bd +/radius1 0 def +/radius2 0 def +/factor 0 def +/rect { +dup type /arraytype eq +{ +pusht x concat +0 0 m 1 0 l 1 1 l 0 1 l closepath +popt +} +{ +/radius2 xd +/radius1 xd +pusht x concat +radius1 radius2 div 1 scale +0 radius2 m +0 1 radius2 1 radius2 arct +radius2 radius1 div +dup 1 1 index 0 radius2 arct +0 0 0 radius2 arct +0 0 0 1 radius2 arct +closepath +popt +} +ifelse +} bd +/buf 0 def +/width 0 def +/height 0 def +/skcimg { +/tmpmat tmpmat currentmatrix def +{ concat } if +/height xd +/width xd +/buf width 3 mul string def +width height scale +width height 8 +[width 0 0 height neg 0 height] +{ currentfile buf readhexstring pop } bind +false 3 colorimage +tmpmat setmatrix +} bd +/skgimg { +/tmpmat tmpmat currentmatrix def +{ concat } if +/height xd +/width xd +/buf width string def +width height scale +width height 8 +[width 0 0 height neg 0 height] +{ currentfile buf readhexstring pop } bind +image +tmpmat setmatrix +} bd +/rclip { +4 2 roll m +dup 0 x rlineto +x 0 rlineto +neg 0 x rlineto +closepath +clip +} bd +/skeps { +10 dict begin +/sk_state save def +concat +3 index neg 3 index neg translate +rclip +0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin +10 setmiterlimit [ ] 0 setdash +newpath +/sk_dict_count countdictstack def +/sk_count count 1 sub def +userdict begin +/showpage { } def +/languagelevel where +{ +pop +languagelevel 1 ne +{ +false setstrokeadjust +false setoverprint +} if +} if +} bd +/skepsend { +count sk_count sub { pop } repeat +countdictstack sk_dict_count sub { end } repeat +sk_state restore +end +} bd +/gradidx 0 def +/gradient { +3 mul array +/gradidx 0 def +} bd +/$ { +3 index gradidx 5 -1 roll put +2 index gradidx 1 add 4 -1 roll put +1 index gradidx 2 add 3 -1 roll put +/gradidx gradidx 3 add def +} bd +/! { +3 +{ +dup dup gradidx dup 3 1 roll 3 sub get put +/gradidx gradidx 1 add def +} +repeat +} bd +/gradcolor { +3 mul dup 2 add 1 exch % idx 1 idx+2 +{ +1 index exch % array array i +get % array component +exch % component array +} +for +4 1 roll +} bd +/x0 0 def /y0 0 def /x1 0 def /y1 0 def +/left 0 def /right 0 def /top 0 def /bottom 0 def +/numcolors 0 def +/axial { +/y1 xd /x1 xd /y0 xd /x0 xd +dup length 3 idiv /numcolors xd +pusht exch % ctm array +x0 x1 ne y0 y1 ne or +{ +x0 y0 translate +[x1 x0 sub y1 y0 sub dup neg 2 index 0 0] concat +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +newpath +0 gradcolor rgb clippath f +0 1 numcolors 1 sub +{ +dup numcolors div +3 1 roll +gradcolor rgb +exch +bottom right top R f +} +for +} +if +pop +popt +} bd +/r0 0 def /r1 0 def /dr 0 def +/radial { +/r1 xd /r0 xd /y0 xd /x0 xd +/dr r1 r0 sub def +dup length 3 idiv /numcolors xd +pusht exch % ctm array +r0 r1 ne +{ +x0 y0 translate +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +newpath +dr 0 gt {numcolors 1 sub}{0} ifelse gradcolor rgb +clippath f +dr 0 gt {numcolors 1 sub -1 0} { 0 1 numcolors 1 sub} ifelse +{ +dup numcolors div dr mul r0 add +3 1 roll +gradcolor rgb +exch +0 0 3 -1 roll C f +} +for +} +if +pop +popt +} bd +/max { +2 copy lt {exch} if pop +} bd +/conical { +pusht 5 1 roll +3 1 roll /y0 xd /x0 xd +x0 y0 translate +radgrad rotate +dup length 3 idiv /numcolors xd +clippath flattenpath pathbbox newpath +4 { abs 4 1 roll} repeat +3 { max } repeat +2 mul +dup scale +0 gradcolor rgb +0 0 1 0 360 arc f +1 1 numcolors 1 sub +{ +dup numcolors div 180 mul +3 1 roll +gradcolor rgb +exch +0 0 moveto +0 0 1 4 -1 roll dup neg arc +closepath f +} +for +pop +popt +} bd +/XStep 0 def /YStep 0 def /imagedata 0 def /components 0 def +/tileimage2 { +exch 4 2 roll +/height xd +/width xd +mark +/components 2 index +/PatternType 1 +/PaintType 1 +/TilingType 1 +/BBox [0 0 width height] +/XStep width +/YStep height +/PaintProc { +begin +XStep YStep 8 +matrix +imagedata +false +components +colorimage +end +} +counttomark 2 div cvi dup dict begin +{ def } repeat +pop currentdict end +dup +/imagedata +4 -1 roll +width height mul mul string +currentfile exch readhexstring pop +put +exch +makepattern +setpattern +clippath +eofill +} bd +/tileimage1 { +concat +/components xd +/height xd +/width xd +/imagedata +currentfile +width height mul components mul string +readhexstring pop +def +clippath flattenpath pathbbox +/top xd /right xd /bottom xd /left xd +left width div floor width mul +bottom height div floor height mul +translate +top bottom sub height div ceiling cvi +{ +gsave +right left sub width div ceiling cvi +{ +width height 8 matrix +components 1 eq +{ +{ imagedata } +image +} +{ +imagedata +false components +colorimage +} +ifelse +width 0 translate +} +repeat +grestore +0 height translate +} +repeat +} bd +/makepattern where +{ +pop +/tileimage /tileimage2 load def +} +{ +/tileimage /tileimage1 load def +} +ifelse +end + + +10.433 setmiterlimit + +SketchDict begin +newpath +473.625 576.087 m +473.625 576.087 478.667 569.965 478.667 569.965 c +478.667 569.965 481.187 559.523 489.109 552.681 c +497.032 545.838 506.214 546.198 506.214 546.198 c +506.214 546.198 520.619 544.217 529.802 540.437 c +538.984 536.656 538.805 536.836 542.046 533.954 c +545.287 531.074 545.287 527.473 542.406 524.952 c +539.525 522.431 534.484 520.27 530.522 519.911 c +526.562 519.55 519.719 519.55 519.719 519.55 c +519.719 519.55 524.04 523.512 524.04 523.512 c +524.04 523.512 534.483 527.112 535.564 528.553 c +536.644 529.994 533.943 531.794 533.943 531.794 c +533.943 531.794 528.002 535.035 523.68 536.115 c +519.359 537.195 499.372 540.977 499.013 540.977 c +498.652 540.977 495.052 541.337 486.229 544.758 c +477.406 548.18 476.146 551.24 476.146 551.24 c +476.146 551.24 468.584 558.802 468.584 558.802 c +468.584 558.802 473.265 576.448 473.265 576.448 c +closepath +0.444 0 0 rgb +F +newpath +442.656 609.577 m +442.656 609.577 443.015 603.456 443.015 603.456 c +443.015 603.456 438.694 600.215 438.694 600.215 c +438.694 600.215 435.093 600.935 431.132 600.575 c +427.171 600.215 416.547 593.553 416.547 593.553 c +416.547 593.553 420.328 587.251 420.328 587.251 c +420.328 587.251 427.171 587.971 427.171 587.971 c +427.171 587.971 428.251 589.051 429.691 587.971 c +431.132 586.89 430.411 586.89 432.212 583.65 c +434.013 580.409 433.293 579.328 433.293 579.328 c +433.293 579.328 431.852 576.448 431.492 574.287 c +431.132 572.126 432.932 562.764 434.733 560.963 c +436.534 559.162 438.334 558.802 438.334 557.002 c +438.334 555.201 438.334 545.838 438.334 545.838 c +438.334 545.838 455.259 543.678 455.259 543.678 c +455.259 543.678 475.785 547.999 475.785 547.999 c +475.785 547.999 476.146 570.326 477.226 573.927 c +478.306 577.528 479.747 577.168 480.107 581.849 c +480.467 586.531 479.026 593.013 479.026 593.013 c +479.026 593.013 478.667 592.652 476.506 600.215 c +474.345 607.777 474.705 609.938 474.705 609.938 c +474.705 609.938 475.065 615.7 475.065 615.7 c +475.065 615.7 442.295 609.938 442.295 610.298 c +closepath +pushc +eoclip newpath +50 gradient +0.677 0 0 $ +! +! +! +! +! +! +! +! +! +! +0.679 0 0 $ +0.685 0 0 $ +0.69 0 0 $ +0.695 0 0 $ +0.7 0 0 $ +0.706 0 0 $ +0.711 0 0 $ +0.716 0 0 $ +0.721 0 0 $ +0.727 0 0 $ +0.732 0 0 $ +0.737 0 0 $ +0.742 0 0 $ +0.748 0 0 $ +0.753 0 0 $ +0.758 0 0 $ +0.763 0 0 $ +0.769 0 0 $ +0.774 0 0 $ +0.779 0 0 $ +0.784 0 0 $ +0.79 0 0 $ +0.795 0 0 $ +0.8 0 0 $ +0.805 0 0 $ +0.811 0 0 $ +0.816 0 0 $ +0.821 0 0 $ +0.826 0 0 $ +0.832 0 0 $ +0.837 0 0 $ +0.842 0 0 $ +0.847 0 0 $ +0.853 0 0 $ +0.858 0 0 $ +0.863 0 0 $ +0.868 0 0 $ +0.874 0 0 $ +0.879 0 0 $ +439.268 598.895 68.713 0 radial +popc +newpath +[14.6696 -1.68454 -2.67069 -23.6151 446.099 580.972] ellipse +pushc +eoclip newpath +50 gradient +0.778 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +0.788 0 0 $ +0.8 0 0 $ +0.811 0 0 $ +0.822 0 0 $ +0.834 0 0 $ +0.845 0 0 $ +0.856 0 0 $ +0.868 0 0 $ +0.879 0 0 $ +0.89 0 0 $ +0.902 0 0 $ +0.913 0 0 $ +0.925 0 0 $ +0.936 0 0 $ +0.947 0 0 $ +0.959 0 0 $ +0.97 0 0 $ +438.644 584.129 34.9312 0 radial +popc +newpath +newpath +428.972 600.575 m +428.251 599.855 430.772 601.655 434.373 601.655 c +437.974 601.655 439.414 600.215 439.414 600.215 c +439.414 600.215 452.738 598.414 452.378 598.055 c +452.018 597.694 457.059 596.253 455.619 592.293 c +454.179 588.331 457.42 588.691 457.06 588.691 c +456.7 588.691 445.536 593.373 442.295 596.614 c +439.055 599.855 437.254 589.051 432.212 588.691 c +427.171 588.331 425.01 586.89 425.01 586.89 c +425.01 586.89 425.01 591.572 425.731 592.652 c +426.451 593.733 428.251 598.774 428.251 598.774 c +closepath +pushc +eoclip newpath +50 gradient +0.455 0 0 $ +0.462 0 0 $ +0.47 0 0 $ +0.477 0 0 $ +0.485 0 0 $ +0.492 0 0 $ +0.499 0 0 $ +0.507 0 0 $ +0.514 0 0 $ +0.522 0 0 $ +0.529 0 0 $ +0.536 0 0 $ +0.544 0 0 $ +0.551 0 0 $ +0.559 0 0 $ +0.566 0 0 $ +0.574 0 0 $ +0.581 0 0 $ +0.588 0 0 $ +0.596 0 0 $ +0.603 0 0 $ +0.611 0 0 $ +0.618 0 0 $ +0.625 0 0 $ +0.633 0 0 $ +0.64 0 0 $ +0.648 0 0 $ +0.655 0 0 $ +0.662 0 0 $ +0.67 0 0 $ +0.677 0 0 $ +0.685 0 0 $ +0.692 0 0 $ +0.699 0 0 $ +0.707 0 0 $ +0.714 0 0 $ +0.722 0 0 $ +0.729 0 0 $ +0.737 0 0 $ +0.744 0 0 $ +0.751 0 0 $ +0.759 0 0 $ +0.766 0 0 $ +0.774 0 0 $ +0.781 0 0 $ +0.788 0 0 $ +0.796 0 0 $ +0.803 0 0 $ +0.811 0 0 $ +0.818 0 0 $ +425.429 602.455 456.669 586.091 axial +popc +newpath +newpath +474.975 612.368 m +474.975 612.368 474.616 608.408 474.795 607.687 c +474.975 606.967 476.596 599.945 476.596 599.765 c +476.596 599.585 479.657 591.122 479.657 591.122 c +479.657 591.122 480.557 587.161 480.197 582.66 c +479.837 578.158 479.117 578.698 477.856 574.917 c +476.596 571.136 476.596 565.914 476.596 565.914 c +476.596 565.914 476.235 556.371 476.056 556.371 c +475.876 556.371 476.596 551.87 475.696 552.951 c +474.795 554.031 469.213 556.011 469.034 556.011 c +468.854 556.011 457.87 556.011 457.87 556.011 c +457.87 556.011 450.128 556.011 450.128 556.011 c +450.128 556.011 445.086 556.732 444.906 556.192 c +444.726 555.651 449.228 560.873 452.828 560.333 c +456.43 559.793 454.99 565.915 454.99 566.275 c +454.99 566.635 463.631 567.535 463.812 569.875 c +463.992 572.216 433.563 578.698 431.763 585 c +429.962 591.302 446.887 579.598 445.086 585.721 c +443.286 591.843 459.851 583.92 460.931 586.441 c +462.012 588.961 465.793 586.62 467.773 588.961 c +469.754 591.302 469.394 591.482 470.114 593.823 c +470.834 596.163 470.654 597.964 470.474 600.125 c +470.294 602.285 469.394 605.706 469.394 606.066 c +469.394 606.427 468.314 606.607 465.612 607.507 c +462.911 608.408 458.05 606.787 454.269 607.147 c +450.488 607.507 449.587 609.488 449.587 609.488 c +449.587 609.488 475.336 612.909 475.336 612.909 c +closepath +pushc +eoclip newpath +50 gradient +1 0 0 $ +0.984 0 0 $ +0.968 0 0 $ +0.951 0 0 $ +0.935 0 0 $ +0.919 0 0 $ +0.903 0 0 $ +0.886 0 0 $ +0.87 0 0 $ +0.854 0 0 $ +0.838 0 0 $ +0.821 0 0 $ +0.805 0 0 $ +0.789 0 0 $ +0.773 0 0 $ +0.756 0 0 $ +0.74 0 0 $ +0.724 0 0 $ +0.708 0 0 $ +0.691 0 0 $ +0.675 0 0 $ +0.659 0 0 $ +0.643 0 0 $ +0.627 0 0 $ +0.61 0 0 $ +0.594 0 0 $ +0.578 0 0 $ +0.562 0 0 $ +0.545 0 0 $ +0.529 0 0 $ +0.513 0 0 $ +0.497 0 0 $ +0.48 0 0 $ +0.464 0 0 $ +0.456 0 0 $ +0.459 0 0 $ +0.461 0 0 $ +0.464 0 0 $ +0.466 0 0 $ +0.469 0 0 $ +0.472 0 0 $ +0.474 0 0 $ +0.477 0 0 $ +0.479 0 0 $ +0.482 0 0 $ +0.485 0 0 $ +0.487 0 0 $ +0.49 0 0 $ +0.492 0 0 $ +0.495 0 0 $ +424.951 602.224 486.96 563.468 axial +popc +newpath +newpath +424.29 654.951 m +424.29 654.951 422.129 670.076 423.21 673.317 c +424.29 676.558 427.531 679.079 430.411 681.24 c +433.293 683.4 436.894 688.441 440.855 690.962 c +444.816 693.483 446.706 693.483 447.337 693.483 c +447.967 693.483 450.218 693.753 450.578 692.763 c +450.939 691.773 450.218 690.242 449.858 690.242 c +449.497 690.242 446.617 687.721 446.256 687.721 c +445.897 687.721 442.205 683.49 441.935 682.32 c +441.665 681.149 441.935 679.079 441.935 679.079 c +441.935 679.079 443.376 675.117 443.736 675.117 c +444.096 675.117 446.977 676.648 448.777 677.278 c +450.578 677.908 450.668 678.088 453.459 678.358 c +456.25 678.628 459.941 678.358 460.301 678.358 c +460.661 678.358 468.314 677.009 468.673 677.009 c +469.034 677.009 474.345 675.117 477.226 673.317 c +480.107 671.517 480.647 670.256 480.647 670.256 c +480.647 670.256 483.348 666.835 483.348 666.835 c +483.348 666.835 485.598 666.565 486.409 665.935 c +487.219 665.304 484.428 665.755 488.029 666.115 c +491.63 666.475 493.971 667.375 493.971 667.375 c +493.971 667.375 494.871 668.996 494.871 668.996 c +494.871 668.996 495.952 671.877 495.952 672.596 c +495.952 673.317 495.232 677.638 495.232 677.999 c +495.232 678.358 494.151 682.32 494.151 682.32 c +494.151 682.32 491.63 685.921 491.63 685.921 c +491.63 685.921 490.55 686.281 490.91 686.281 c +491.271 686.281 490.19 687.001 493.431 687.361 c +496.672 687.721 499.013 684.841 500.273 683.76 c +501.534 682.68 507.295 678.179 509.096 673.497 c +510.897 668.816 510.897 664.314 510.177 661.073 c +509.456 657.833 507.115 654.591 505.855 652.43 c +504.595 650.27 500.993 647.389 499.192 646.309 c +497.392 645.229 491.271 642.347 491.271 642.347 c +491.271 642.347 490.19 641.267 489.83 639.827 c +489.47 638.387 490.19 630.824 490.19 630.824 c +490.19 630.824 489.83 625.422 488.029 622.901 c +486.229 620.381 480.107 617.32 480.107 617.32 c +480.107 617.32 476.866 614.259 474.705 612.098 c +472.545 609.938 462.101 607.958 457.78 608.317 c +453.459 608.678 455.619 608.317 452.738 607.957 c +449.858 607.597 446.617 607.777 446.617 607.777 c +446.617 607.777 443.015 607.777 438.694 609.577 c +434.373 611.378 433.653 612.098 433.293 612.459 c +432.932 612.818 426.991 617.68 426.991 617.68 c +426.991 617.68 422.849 620.381 421.049 621.101 c +419.248 621.821 417.448 625.063 416.368 627.223 c +415.287 629.384 415.287 631.544 415.287 631.544 c +415.287 631.544 414.026 633.885 416.547 637.846 c +419.068 641.807 419.068 639.467 421.589 643.788 c +424.11 648.109 421.949 643.068 423.39 647.389 c +424.83 651.71 424.29 657.112 424.29 657.112 c +closepath +pushc +eoclip newpath +50 gradient +0.626 0 0 $ +0.631 0 0 $ +0.636 0 0 $ +0.641 0 0 $ +0.645 0 0 $ +0.65 0 0 $ +0.655 0 0 $ +0.66 0 0 $ +0.665 0 0 $ +0.67 0 0 $ +0.674 0 0 $ +0.681 0 0 $ +0.689 0 0 $ +0.698 0 0 $ +0.706 0 0 $ +0.714 0 0 $ +0.723 0 0 $ +0.731 0 0 $ +0.74 0 0 $ +0.748 0 0 $ +0.756 0 0 $ +0.765 0 0 $ +0.773 0 0 $ +0.782 0 0 $ +0.79 0 0 $ +0.798 0 0 $ +0.807 0 0 $ +0.815 0 0 $ +0.824 0 0 $ +0.832 0 0 $ +0.84 0 0 $ +0.849 0 0 $ +0.857 0 0 $ +0.866 0 0 $ +0.874 0 0 $ +0.882 0 0 $ +0.891 0 0 $ +0.899 0 0 $ +0.908 0 0 $ +0.916 0 0 $ +0.924 0 0 $ +0.933 0 0 $ +0.941 0 0 $ +0.95 0 0 $ +0.958 0 0 $ +0.966 0 0 $ +0.975 0 0 $ +0.983 0 0 $ +0.992 0 0 $ +1 0 0 $ +446.857 653.484 78.4847 0 radial +popc +newpath +newpath +425.731 647.389 m +425.731 647.389 426.631 652.971 426.631 652.971 c +426.631 652.971 428.611 656.032 428.611 656.392 c +428.611 656.752 430.772 660.173 432.572 661.973 c +434.373 663.774 439.055 666.475 439.055 666.475 c +439.055 666.475 441.935 667.375 442.656 666.115 c +443.376 664.855 443.196 665.755 442.475 663.594 c +441.755 661.433 440.135 658.913 440.135 658.913 c +440.135 658.913 438.334 656.752 437.614 653.871 c +436.894 650.99 436.894 650.27 436.894 650.27 c +436.894 650.27 436.173 647.029 436.173 647.029 c +436.173 647.029 434.373 643.788 434.373 643.788 c +434.373 643.788 433.653 641.988 433.653 641.988 c +433.653 641.988 431.132 640.907 431.132 640.907 c +431.132 640.907 427.531 641.988 427.531 641.988 c +427.531 641.988 425.91 644.148 425.731 645.229 c +425.55 646.309 425.731 647.389 425.731 647.389 c +closepath +pushc +eoclip newpath +50 gradient +0.737 0.737 0.737 $ +0.746 0.746 0.746 $ +0.755 0.755 0.755 $ +0.764 0.764 0.764 $ +0.773 0.773 0.773 $ +0.782 0.782 0.782 $ +0.792 0.792 0.792 $ +0.801 0.801 0.801 $ +0.81 0.81 0.81 $ +0.819 0.819 0.819 $ +0.828 0.828 0.828 $ +0.837 0.837 0.837 $ +0.846 0.846 0.846 $ +0.855 0.855 0.855 $ +0.864 0.864 0.864 $ +0.873 0.873 0.873 $ +0.883 0.883 0.883 $ +0.892 0.892 0.892 $ +0.901 0.901 0.901 $ +0.91 0.91 0.91 $ +0.919 0.919 0.919 $ +0.928 0.928 0.928 $ +0.937 0.937 0.937 $ +0.946 0.946 0.946 $ +0.955 0.955 0.955 $ +0.964 0.964 0.964 $ +0.974 0.974 0.974 $ +0.983 0.983 0.983 $ +0.992 0.992 0.992 $ +1 1 1 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +427.937 655.141 20.8071 0 radial +popc +newpath +newpath +442.205 653.961 m +442.205 653.961 444.546 658.283 446.347 660.623 c +448.147 662.964 447.967 664.044 450.488 664.585 c +453.009 665.125 454.089 664.945 456.25 663.324 c +458.41 661.703 460.031 659.183 460.391 656.122 c +460.751 653.061 460.571 644.598 459.671 641.898 c +458.771 639.197 456.609 634.695 455.17 633.435 c +453.729 632.175 453.729 631.094 450.308 630.734 c +446.887 630.374 446.707 630.374 444.546 631.454 c +442.386 632.535 440.585 634.695 440.585 634.876 c +440.585 635.055 438.424 639.737 438.424 641.537 c +438.424 643.338 440.405 650.54 440.405 650.72 c +440.405 650.9 442.566 654.502 442.566 654.502 c +closepath +pushc +eoclip newpath +50 gradient +0.737 0.737 0.737 $ +0.746 0.746 0.746 $ +0.755 0.755 0.755 $ +0.764 0.764 0.764 $ +0.773 0.773 0.773 $ +0.782 0.782 0.782 $ +0.792 0.792 0.792 $ +0.801 0.801 0.801 $ +0.81 0.81 0.81 $ +0.819 0.819 0.819 $ +0.828 0.828 0.828 $ +0.837 0.837 0.837 $ +0.846 0.846 0.846 $ +0.855 0.855 0.855 $ +0.864 0.864 0.864 $ +0.873 0.873 0.873 $ +0.883 0.883 0.883 $ +0.892 0.892 0.892 $ +0.901 0.901 0.901 $ +0.91 0.91 0.91 $ +0.919 0.919 0.919 $ +0.928 0.928 0.928 $ +0.937 0.937 0.937 $ +0.946 0.946 0.946 $ +0.955 0.955 0.955 $ +0.964 0.964 0.964 $ +0.974 0.974 0.974 $ +0.983 0.983 0.983 $ +0.992 0.992 0.992 $ +1 1 1 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +440.796 648.261 26.5629 0 radial +popc +newpath +[5.36527 -1.21705 -1.81379 -8.99236 443.376 642.978] ellipse +pushc +eoclip newpath +50 gradient +0 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +0.013 0.013 0.013 $ +0.045 0.045 0.045 $ +0.078 0.078 0.078 $ +0.11 0.11 0.11 $ +0.143 0.143 0.143 $ +0.176 0.176 0.176 $ +0.208 0.208 0.208 $ +0.241 0.241 0.241 $ +0.273 0.273 0.273 $ +0.306 0.306 0.306 $ +0.338 0.338 0.338 $ +0.371 0.371 0.371 $ +0.403 0.403 0.403 $ +0.436 0.436 0.436 $ +0.468 0.468 0.468 $ +0.501 0.501 0.501 $ +0.533 0.533 0.533 $ +0.566 0.566 0.566 $ +442.162 646.91 14.7128 0 radial +popc +newpath +[3.50831 -0.944447 -1.42027 -6.48433 429.085 647.862] ellipse +pushc +eoclip newpath +50 gradient +0 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +0.013 0.013 0.013 $ +0.045 0.045 0.045 $ +0.078 0.078 0.078 $ +0.11 0.11 0.11 $ +0.143 0.143 0.143 $ +0.176 0.176 0.176 $ +0.208 0.208 0.208 $ +0.241 0.241 0.241 $ +0.273 0.273 0.273 $ +0.306 0.306 0.306 $ +0.338 0.338 0.338 $ +0.371 0.371 0.371 $ +0.403 0.403 0.403 $ +0.436 0.436 0.436 $ +0.468 0.468 0.468 $ +0.501 0.501 0.501 $ +0.533 0.533 0.533 $ +0.566 0.566 0.566 $ +427.643 651.138 11.1324 0 radial +popc +newpath +[0.500026 -0.204317 -0.340534 -0.833389 428.161 651.08] ellipse +1 1 1 rgb +F +[0.681665 -0.232484 -0.435916 -1.27814 442.408 647.052] ellipse +F +newpath +493.791 685.561 m +493.791 685.561 495.592 681.96 497.752 678.358 c +499.913 674.757 501.354 672.957 500.633 669.716 c +499.913 666.475 495.952 662.874 495.592 662.874 c +495.232 662.874 490.91 657.832 486.229 657.472 c +481.547 657.112 479.387 658.913 476.866 656.032 c +474.345 653.151 472.545 647.749 471.825 644.868 c +471.104 641.988 473.985 638.026 472.905 632.625 c +471.825 627.223 471.104 623.262 469.304 621.461 c +467.503 619.66 465.702 616.06 462.462 614.619 c +459.221 613.179 457.06 612.098 457.06 612.098 c +457.06 612.098 442.295 610.298 442.295 610.298 c +442.295 610.298 446.256 609.577 450.218 609.577 c +454.179 609.577 455.079 608.498 458.68 608.857 c +462.282 609.218 467.683 610.118 471.645 611.558 c +475.606 612.999 475.426 615.159 479.747 617.68 c +484.068 620.201 488.03 620.561 489.83 626.323 c +491.63 632.085 487.849 638.747 491.09 641.448 c +494.331 644.148 501.534 646.669 504.054 649.91 c +506.575 653.151 510.717 657.652 510.356 665.575 c +509.996 673.497 506.755 673.677 504.234 677.638 c +501.713 681.599 493.791 685.921 493.791 685.921 c +closepath +pushc +eoclip newpath +50 gradient +1 0 0 $ +0.99 0 0 $ +0.98 0 0 $ +0.97 0 0 $ +0.96 0 0 $ +0.95 0 0 $ +0.94 0 0 $ +0.93 0 0 $ +0.92 0 0 $ +0.91 0 0 $ +0.9 0 0 $ +0.89 0 0 $ +0.88 0 0 $ +0.87 0 0 $ +0.86 0 0 $ +0.85 0 0 $ +0.831 0 0 $ +0.809 0 0 $ +0.788 0 0 $ +0.767 0 0 $ +0.745 0 0 $ +0.724 0 0 $ +0.702 0 0 $ +0.681 0 0 $ +0.66 0 0 $ +0.638 0 0 $ +0.617 0 0 $ +0.595 0 0 $ +0.574 0 0 $ +0.553 0 0 $ +0.531 0 0 $ +0.51 0 0 $ +0.488 0 0 $ +0.467 0 0 $ +0.455 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +434.343 660.475 518.33 634.229 axial +popc +newpath +newpath +443.736 692.043 m +443.736 692.043 438.334 684.841 437.974 684.841 c +437.614 684.841 434.013 681.24 432.212 677.638 c +430.411 674.037 432.212 668.996 432.212 668.996 c +432.212 668.996 428.251 661.794 428.251 661.794 c +428.251 661.794 434.733 668.996 434.733 668.996 c +434.733 668.996 437.974 673.317 437.974 673.317 c +437.974 673.317 440.135 673.317 441.575 674.397 c +443.015 675.478 439.775 678.719 440.135 680.519 c +440.495 682.32 441.576 685.2 444.816 687.361 c +448.057 689.522 449.228 689.882 449.498 691.053 c +449.768 692.223 448.507 692.673 448.507 692.673 c +448.507 692.673 445.806 692.493 444.456 692.403 c +closepath +pushc +eoclip newpath +50 gradient +0.848 0 0 $ +0.836 0 0 $ +0.825 0 0 $ +0.813 0 0 $ +0.801 0 0 $ +0.789 0 0 $ +0.778 0 0 $ +0.766 0 0 $ +0.754 0 0 $ +0.743 0 0 $ +0.731 0 0 $ +0.719 0 0 $ +0.707 0 0 $ +0.696 0 0 $ +0.684 0 0 $ +0.672 0 0 $ +0.661 0 0 $ +0.649 0 0 $ +0.637 0 0 $ +0.626 0 0 $ +0.614 0 0 $ +0.602 0 0 $ +0.59 0 0 $ +0.579 0 0 $ +0.567 0 0 $ +0.555 0 0 $ +0.544 0 0 $ +0.532 0 0 $ +0.52 0 0 $ +0.508 0 0 $ +0.497 0 0 $ +0.485 0 0 $ +0.473 0 0 $ +0.462 0 0 $ +0.452 0 0 $ +0.444 0 0 $ +0.436 0 0 $ +0.428 0 0 $ +0.42 0 0 $ +0.412 0 0 $ +0.404 0 0 $ +0.396 0 0 $ +0.388 0 0 $ +0.38 0 0 $ +0.373 0 0 $ +0.365 0 0 $ +0.357 0 0 $ +0.349 0 0 $ +0.341 0 0 $ +0.333 0 0 $ +424.233 685.785 453.554 668.682 axial +popc +newpath +newpath +442.656 672.957 m +442.295 672.957 443.736 669.716 444.456 669.716 c +445.176 669.716 445.176 671.877 446.977 674.037 c +448.777 676.198 455.98 676.918 455.98 675.838 c +455.98 674.758 450.578 671.516 451.298 670.796 c +452.018 670.076 456.339 670.796 458.14 669.716 c +459.941 668.636 462.462 662.874 463.542 663.234 c +464.622 663.594 464.622 669.356 467.503 669.716 c +470.384 670.076 481.367 663.594 484.248 663.234 c +487.129 662.874 493.161 667.375 493.161 667.015 c +493.161 666.655 487.669 665.214 484.788 666.475 c +481.907 667.736 480.287 672.056 476.326 673.857 c +472.365 675.658 469.124 676.558 465.882 677.638 c +462.641 678.719 454.899 678.538 453.999 678.538 c +453.099 678.538 446.976 676.918 446.617 676.558 c +446.256 676.198 442.295 673.317 442.295 673.317 c +closepath +pushc +eoclip newpath +50 gradient +0.929 0 0 $ +0.915 0 0 $ +0.901 0 0 $ +0.887 0 0 $ +0.873 0 0 $ +0.858 0 0 $ +0.844 0 0 $ +0.83 0 0 $ +0.816 0 0 $ +0.802 0 0 $ +0.788 0 0 $ +0.774 0 0 $ +0.76 0 0 $ +0.745 0 0 $ +0.731 0 0 $ +0.717 0 0 $ +0.703 0 0 $ +0.689 0 0 $ +0.675 0 0 $ +0.661 0 0 $ +0.647 0 0 $ +0.632 0 0 $ +0.618 0 0 $ +0.604 0 0 $ +0.59 0 0 $ +0.576 0 0 $ +0.562 0 0 $ +0.548 0 0 $ +0.534 0 0 $ +0.519 0 0 $ +0.505 0 0 $ +0.491 0 0 $ +0.477 0 0 $ +0.463 0 0 $ +0.452 0 0 $ +0.444 0 0 $ +0.436 0 0 $ +0.428 0 0 $ +0.42 0 0 $ +0.412 0 0 $ +0.404 0 0 $ +0.396 0 0 $ +0.388 0 0 $ +0.38 0 0 $ +0.373 0 0 $ +0.365 0 0 $ +0.357 0 0 $ +0.349 0 0 $ +0.341 0 0 $ +0.333 0 0 $ +461.749 655.601 473.707 686.162 axial +popc +newpath +[8.98414 -1.89974 -1.2665 -5.98943 433.112 634.785] ellipse +pushc +eoclip newpath +50 gradient +0.424 0 0 $ +0.425 0 0 $ +0.426 0 0 $ +0.427 0 0 $ +0.428 0 0 $ +0.43 0 0 $ +0.431 0 0 $ +0.432 0 0 $ +0.433 0 0 $ +0.434 0 0 $ +0.435 0 0 $ +0.436 0 0 $ +0.437 0 0 $ +0.439 0 0 $ +0.44 0 0 $ +0.441 0 0 $ +0.442 0 0 $ +0.443 0 0 $ +0.444 0 0 $ +0.445 0 0 $ +0.446 0 0 $ +0.448 0 0 $ +0.449 0 0 $ +0.45 0 0 $ +0.451 0 0 $ +0.452 0 0 $ +0.453 0 0 $ +0.454 0 0 $ +0.463 0 0 $ +0.489 0 0 $ +0.515 0 0 $ +0.541 0 0 $ +0.566 0 0 $ +0.592 0 0 $ +0.618 0 0 $ +0.644 0 0 $ +0.67 0 0 $ +0.695 0 0 $ +0.721 0 0 $ +0.747 0 0 $ +0.773 0 0 $ +0.799 0 0 $ +0.824 0 0 $ +0.828 0 0 $ +! +! +! +! +! +! +430.304 636.461 14.3008 0 radial +popc +newpath +newpath +449.137 618.94 m +449.137 618.94 455.259 621.461 457.78 621.822 c +460.301 622.181 463.182 622.181 464.982 620.741 c +466.783 619.3 466.063 617.5 465.702 617.5 c +465.342 617.5 460.301 616.78 457.06 615.7 c +453.819 614.619 452.018 612.098 446.977 611.738 c +441.935 611.378 443.376 609.938 437.614 611.738 c +431.852 613.539 431.492 613.899 429.331 616.06 c +427.171 618.22 423.57 622.901 423.57 622.901 c +423.57 622.901 423.21 626.863 423.21 626.863 c +423.21 626.863 424.29 627.943 427.891 624.702 c +431.492 621.461 433.652 622.181 437.254 619.66 c +440.855 617.14 439.414 618.58 444.096 618.22 c +448.777 617.86 448.417 619.3 448.417 619.3 c +closepath +0.636 0 0 rgb +F +newpath +400.523 635.505 m +400.523 635.505 406.285 624.702 406.285 624.702 c +406.285 624.702 408.445 626.863 408.806 626.863 c +409.165 626.863 412.406 623.622 412.046 621.821 c +411.686 620.021 408.445 616.06 408.445 616.06 c +408.445 616.06 402.323 620.741 402.323 621.101 c +402.323 621.461 404.124 624.342 403.764 624.342 c +403.403 624.342 395.121 626.143 395.121 626.143 c +395.121 626.143 397.282 617.86 397.282 617.86 c +397.282 617.86 399.442 619.301 399.442 619.301 c +399.442 619.301 406.285 613.179 406.285 613.539 c +406.285 613.899 404.484 609.218 400.162 608.857 c +395.841 608.497 394.401 611.018 394.401 611.018 c +394.401 611.018 394.761 613.899 394.761 613.899 c +394.761 613.899 384.678 615.339 384.678 615.339 c +384.678 615.339 385.218 610.838 390.26 607.957 c +395.301 605.076 397.462 603.996 403.224 606.157 c +408.985 608.317 409.346 609.758 409.346 609.758 c +409.346 609.758 409.886 610.298 409.886 610.298 c +409.886 610.298 415.287 605.256 415.287 605.256 c +415.287 605.256 418.528 609.938 418.528 609.938 c +418.528 609.938 412.766 614.259 412.766 614.259 c +412.766 614.259 414.927 617.5 414.927 617.5 c +414.927 617.5 416.547 621.641 415.107 625.242 c +413.667 628.843 410.966 630.464 410.966 630.464 c +410.966 630.464 408.445 632.625 405.564 633.705 c +402.683 634.785 401.243 634.785 401.243 634.785 c +closepath +pushc +eoclip newpath +50 gradient +0.737 0.737 0.737 $ +0.731 0.731 0.731 $ +0.725 0.725 0.725 $ +0.718 0.718 0.718 $ +0.712 0.712 0.712 $ +0.706 0.706 0.706 $ +0.7 0.7 0.7 $ +0.694 0.694 0.694 $ +0.687 0.687 0.687 $ +0.681 0.681 0.681 $ +0.675 0.675 0.675 $ +0.669 0.669 0.669 $ +0.663 0.663 0.663 $ +0.656 0.656 0.656 $ +0.65 0.65 0.65 $ +0.644 0.644 0.644 $ +0.638 0.638 0.638 $ +0.631 0.631 0.631 $ +0.625 0.625 0.625 $ +0.619 0.619 0.619 $ +0.613 0.613 0.613 $ +0.607 0.607 0.607 $ +0.6 0.6 0.6 $ +0.594 0.594 0.594 $ +0.588 0.588 0.588 $ +0.582 0.582 0.582 $ +0.576 0.576 0.576 $ +0.569 0.569 0.569 $ +0.563 0.563 0.563 $ +0.557 0.557 0.557 $ +0.537 0.537 0.537 $ +0.514 0.514 0.514 $ +0.492 0.492 0.492 $ +0.469 0.469 0.469 $ +0.446 0.446 0.446 $ +0.424 0.424 0.424 $ +0.401 0.401 0.401 $ +0.384 0.384 0.384 $ +! +! +! +! +! +! +! +! +! +! +! +! +382.433 631.763 420.773 608.758 axial +popc +newpath +[6.26125 -1.34636 -0.426261 -8.21329 424.516 594.859] ellipse +pushc +eoclip newpath +50 gradient +0.424 0 0 $ +0.431 0 0 $ +0.438 0 0 $ +0.444 0 0 $ +0.451 0 0 $ +0.458 0 0 $ +0.465 0 0 $ +0.472 0 0 $ +0.479 0 0 $ +0.485 0 0 $ +0.492 0 0 $ +0.499 0 0 $ +0.506 0 0 $ +0.513 0 0 $ +0.519 0 0 $ +0.526 0 0 $ +0.533 0 0 $ +0.54 0 0 $ +0.547 0 0 $ +0.554 0 0 $ +0.56 0 0 $ +0.567 0 0 $ +0.574 0 0 $ +0.581 0 0 $ +0.588 0 0 $ +0.594 0 0 $ +0.601 0 0 $ +0.608 0 0 $ +0.615 0 0 $ +0.622 0 0 $ +0.628 0 0 $ +0.635 0 0 $ +0.642 0 0 $ +0.649 0 0 $ +0.656 0 0 $ +0.663 0 0 $ +0.669 0 0 $ +0.676 0 0 $ +0.683 0 0 $ +0.69 0 0 $ +0.697 0 0 $ +0.703 0 0 $ +0.71 0 0 $ +0.717 0 0 $ +0.724 0 0 $ +0.731 0 0 $ +0.738 0 0 $ +0.744 0 0 $ +0.751 0 0 $ +0.758 0 0 $ +422.275 598.188 14.4331 0 radial +popc +newpath +newpath +442.655 600.575 m +442.655 600.575 443.376 604.536 446.256 605.256 c +449.138 605.977 453.818 602.735 454.179 602.735 c +454.539 602.735 458.5 603.816 463.182 602.015 c +467.863 600.215 467.863 597.694 465.342 595.894 c +462.822 594.093 466.063 591.932 463.542 591.573 c +461.022 591.212 460.661 590.851 458.86 592.293 c +457.06 593.733 455.259 599.494 454.899 599.494 c +454.539 599.494 448.777 600.575 448.417 600.575 c +448.057 600.575 443.015 600.215 443.015 600.215 c +closepath +pushc +eoclip newpath +50 gradient +0.778 0 0 $ +0.772 0 0 $ +0.765 0 0 $ +0.759 0 0 $ +0.752 0 0 $ +0.746 0 0 $ +0.74 0 0 $ +0.733 0 0 $ +0.727 0 0 $ +0.721 0 0 $ +0.714 0 0 $ +0.708 0 0 $ +0.701 0 0 $ +0.695 0 0 $ +0.689 0 0 $ +0.682 0 0 $ +0.676 0 0 $ +0.669 0 0 $ +0.663 0 0 $ +0.657 0 0 $ +0.65 0 0 $ +0.644 0 0 $ +0.637 0 0 $ +0.631 0 0 $ +0.625 0 0 $ +0.618 0 0 $ +0.612 0 0 $ +0.606 0 0 $ +0.599 0 0 $ +0.593 0 0 $ +0.586 0 0 $ +0.58 0 0 $ +0.574 0 0 $ +0.567 0 0 $ +0.561 0 0 $ +0.554 0 0 $ +0.548 0 0 $ +0.542 0 0 $ +0.535 0 0 $ +0.529 0 0 $ +0.522 0 0 $ +0.516 0 0 $ +0.51 0 0 $ +0.503 0 0 $ +0.497 0 0 $ +0.491 0 0 $ +0.484 0 0 $ +0.478 0 0 $ +0.471 0 0 $ +0.465 0 0 $ +454.84 605.361 454.84 591.25 axial +popc +newpath +[5.36305 -1.08423 -0.365113 -6.61418 420.735 593.239] ellipse +pushc +eoclip newpath +50 gradient +0.424 0 0 $ +0.425 0 0 $ +0.426 0 0 $ +0.427 0 0 $ +0.428 0 0 $ +0.43 0 0 $ +0.431 0 0 $ +0.432 0 0 $ +0.433 0 0 $ +0.434 0 0 $ +0.435 0 0 $ +0.436 0 0 $ +0.437 0 0 $ +0.439 0 0 $ +0.44 0 0 $ +0.441 0 0 $ +0.442 0 0 $ +0.443 0 0 $ +0.444 0 0 $ +0.445 0 0 $ +0.446 0 0 $ +0.448 0 0 $ +0.449 0 0 $ +0.45 0 0 $ +0.451 0 0 $ +0.452 0 0 $ +0.453 0 0 $ +0.454 0 0 $ +0.463 0 0 $ +0.489 0 0 $ +0.515 0 0 $ +0.541 0 0 $ +0.566 0 0 $ +0.592 0 0 $ +0.618 0 0 $ +0.644 0 0 $ +0.67 0 0 $ +0.695 0 0 $ +0.721 0 0 $ +0.747 0 0 $ +0.773 0 0 $ +0.799 0 0 $ +0.824 0 0 $ +0.828 0 0 $ +! +! +! +! +! +! +419.172 595.338 11.2075 0 radial +popc +newpath +newpath +527.641 524.952 m +522.96 522.791 l +519.359 531.074 l +511.437 522.791 l +497.752 514.149 l +519.359 514.869 l +528.362 514.869 l +538.805 516.309 l +531.242 518.83 l +535.924 522.791 l +537.365 526.392 l +534.124 526.753 l +526.921 524.772 l +closepath +pushc +eoclip newpath +50 gradient +0.475 0 0 $ +0.474 0 0 $ +0.474 0 0 $ +0.473 0 0 $ +0.473 0 0 $ +0.472 0 0 $ +0.471 0 0 $ +0.471 0 0 $ +0.47 0 0 $ +0.47 0 0 $ +0.469 0 0 $ +0.468 0 0 $ +0.468 0 0 $ +0.467 0 0 $ +0.467 0 0 $ +0.466 0 0 $ +0.465 0 0 $ +0.465 0 0 $ +0.464 0 0 $ +0.464 0 0 $ +0.463 0 0 $ +0.462 0 0 $ +0.462 0 0 $ +0.461 0 0 $ +0.461 0 0 $ +0.46 0 0 $ +0.46 0 0 $ +0.459 0 0 $ +0.458 0 0 $ +0.458 0 0 $ +0.457 0 0 $ +0.457 0 0 $ +0.456 0 0 $ +0.455 0 0 $ +0.461 0 0 $ +0.476 0 0 $ +0.49 0 0 $ +0.504 0 0 $ +0.519 0 0 $ +0.533 0 0 $ +0.548 0 0 $ +0.562 0 0 $ +0.576 0 0 $ +0.591 0 0 $ +0.605 0 0 $ +0.619 0 0 $ +0.634 0 0 $ +0.648 0 0 $ +0.663 0 0 $ +0.677 0 0 $ +513.88 522.611 26.3224 0 radial +popc +newpath +[8.05766 -0.851211 -0.548558 -5.1927 421.229 605.796] ellipse +pushc +eoclip newpath +50 gradient +0.424 0 0 $ +0.425 0 0 $ +0.426 0 0 $ +0.427 0 0 $ +0.428 0 0 $ +0.43 0 0 $ +0.431 0 0 $ +0.432 0 0 $ +0.433 0 0 $ +0.434 0 0 $ +0.435 0 0 $ +0.436 0 0 $ +0.437 0 0 $ +0.439 0 0 $ +0.44 0 0 $ +0.441 0 0 $ +0.442 0 0 $ +0.443 0 0 $ +0.444 0 0 $ +0.445 0 0 $ +0.446 0 0 $ +0.448 0 0 $ +0.449 0 0 $ +0.45 0 0 $ +0.451 0 0 $ +0.452 0 0 $ +0.453 0 0 $ +0.454 0 0 $ +0.463 0 0 $ +0.489 0 0 $ +0.515 0 0 $ +0.541 0 0 $ +0.566 0 0 $ +0.592 0 0 $ +0.618 0 0 $ +0.644 0 0 $ +0.67 0 0 $ +0.695 0 0 $ +0.721 0 0 $ +0.747 0 0 $ +0.773 0 0 $ +0.799 0 0 $ +0.824 0 0 $ +0.828 0 0 $ +! +! +! +! +! +! +418.881 607.444 12.5065 0 radial +popc +newpath +[8.05766 -0.851211 -0.548558 -5.1927 417.831 599.877] ellipse +pushc +eoclip newpath +50 gradient +0.424 0 0 $ +0.425 0 0 $ +0.426 0 0 $ +0.427 0 0 $ +0.428 0 0 $ +0.43 0 0 $ +0.431 0 0 $ +0.432 0 0 $ +0.433 0 0 $ +0.434 0 0 $ +0.435 0 0 $ +0.436 0 0 $ +0.437 0 0 $ +0.439 0 0 $ +0.44 0 0 $ +0.441 0 0 $ +0.442 0 0 $ +0.443 0 0 $ +0.444 0 0 $ +0.445 0 0 $ +0.446 0 0 $ +0.448 0 0 $ +0.449 0 0 $ +0.45 0 0 $ +0.451 0 0 $ +0.452 0 0 $ +0.453 0 0 $ +0.454 0 0 $ +0.463 0 0 $ +0.489 0 0 $ +0.515 0 0 $ +0.541 0 0 $ +0.566 0 0 $ +0.592 0 0 $ +0.618 0 0 $ +0.644 0 0 $ +0.67 0 0 $ +0.695 0 0 $ +0.721 0 0 $ +0.747 0 0 $ +0.773 0 0 $ +0.799 0 0 $ +0.824 0 0 $ +0.828 0 0 $ +! +! +! +! +! +! +415.483 601.525 12.5065 0 radial +popc +newpath +newpath +416.727 544.758 m +417.088 544.758 428.972 546.558 430.052 546.558 c +431.132 546.558 434.733 546.919 436.173 548.719 c +437.614 550.52 436.534 552.681 436.534 552.681 c +436.534 552.681 434.733 558.082 435.093 558.442 c +435.453 558.802 444.456 557.002 444.456 557.002 c +444.456 557.002 450.938 557.362 452.378 555.561 c +453.819 553.761 452.739 547.999 452.739 547.999 c +452.739 547.999 450.218 544.037 449.858 544.037 c +449.497 544.037 445.536 541.517 440.495 540.797 c +435.453 540.077 435.814 542.598 431.132 541.157 c +426.451 539.716 422.849 537.556 422.849 537.556 c +422.849 537.556 417.448 544.758 417.448 544.758 c +closepath +pushc +eoclip newpath +50 gradient +0.556 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +0.564 0 0 $ +0.574 0 0 $ +0.585 0 0 $ +0.595 0 0 $ +0.606 0 0 $ +0.617 0 0 $ +0.627 0 0 $ +0.638 0 0 $ +0.648 0 0 $ +0.659 0 0 $ +0.669 0 0 $ +0.68 0 0 $ +0.691 0 0 $ +0.701 0 0 $ +0.712 0 0 $ +0.722 0 0 $ +0.733 0 0 $ +0.743 0 0 $ +0.754 0 0 $ +0.765 0 0 $ +0.775 0 0 $ +0.786 0 0 $ +0.796 0 0 $ +0.807 0 0 $ +0.817 0 0 $ +0.828 0 0 $ +432.761 549.418 23.5697 0 radial +popc +newpath +newpath +435.453 555.561 m +435.453 555.921 434.373 558.442 434.373 558.442 c +434.373 558.442 441.215 558.082 441.215 558.082 c +441.215 558.082 446.977 557.002 446.977 557.002 c +446.977 557.002 451.298 556.641 451.298 556.641 c +451.298 556.641 452.739 553.761 452.739 553.761 c +452.739 553.761 453.098 550.88 453.098 550.88 c +453.098 550.88 446.617 552.32 446.256 552.681 c +445.897 553.04 439.775 554.841 439.414 554.841 c +439.055 554.841 435.453 557.002 435.453 557.002 c +closepath +0.434 0 0 rgb +F +newpath +452.018 551.6 m +452.018 551.6 453.098 550.88 452.018 547.639 c +450.938 544.398 449.498 544.037 449.138 544.037 c +448.777 544.037 446.256 542.237 446.256 542.237 c +0.475 0 0 rgb +1 w +0 j +0 J +[] 0 d +S +newpath +434.373 558.442 m +434.373 558.442 434.733 558.082 435.814 555.201 c +436.894 552.32 437.974 554.12 436.534 550.52 c +435.093 546.919 434.733 547.278 434.733 547.278 c +434.733 547.278 432.932 547.278 432.932 547.278 c +S +newpath +475.065 553.401 m +475.065 553.401 476.866 545.478 476.866 545.118 c +476.866 544.758 479.747 539.356 479.387 539.356 c +479.026 539.356 475.426 537.195 471.464 535.755 c +467.503 534.315 462.462 531.794 459.221 531.434 c +455.98 531.074 446.256 531.794 446.256 531.794 c +446.256 531.794 445.897 535.395 441.575 537.916 c +437.254 540.437 428.972 541.517 428.972 541.517 c +428.972 541.517 439.775 543.678 439.775 543.678 c +439.775 543.678 448.777 545.478 448.777 545.478 c +448.777 545.478 450.218 554.481 450.218 554.481 c +450.218 554.481 455.619 555.561 455.98 555.561 c +456.339 555.561 467.863 555.921 468.223 555.921 c +468.584 555.921 474.345 554.12 474.345 554.12 c +closepath +pushc +eoclip newpath +50 gradient +0.556 0 0 $ +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +0.564 0 0 $ +0.574 0 0 $ +0.585 0 0 $ +0.595 0 0 $ +0.606 0 0 $ +0.617 0 0 $ +0.627 0 0 $ +0.638 0 0 $ +0.648 0 0 $ +0.659 0 0 $ +0.669 0 0 $ +0.68 0 0 $ +0.691 0 0 $ +0.701 0 0 $ +0.712 0 0 $ +0.722 0 0 $ +0.733 0 0 $ +0.743 0 0 $ +0.754 0 0 $ +0.765 0 0 $ +0.775 0 0 $ +0.786 0 0 $ +0.796 0 0 $ +0.807 0 0 $ +0.817 0 0 $ +0.828 0 0 $ +451.192 545.266 31.4774 0 radial +popc +newpath +newpath +453.098 555.561 m +463.542 559.162 l +473.265 559.523 l +475.785 553.401 l +476.866 547.639 l +477.586 543.318 l +474.705 546.198 l +467.863 549.079 l +458.14 550.88 l +453.098 552.32 l +450.938 554.481 l +452.739 555.921 l +closepath +0.434 0 0 rgb +F +453.098 555.561 m +463.542 559.162 l +473.265 559.523 l +475.785 553.401 l +476.866 547.639 l +477.586 543.318 l +474.705 546.198 l +467.863 549.079 l +458.14 550.88 l +453.098 552.32 l +450.938 554.481 l +452.739 555.921 l +0.475 0 0 rgb +1 w +0 j +0 J +[] 0 d +S +[15.1246 0 0 -7.74233 413.127 537.735] ellipse +pushc +eoclip newpath +50 gradient +0.576 0.576 0.576 $ +0.585 0.585 0.585 $ +0.593 0.593 0.593 $ +0.602 0.602 0.602 $ +0.611 0.611 0.611 $ +0.619 0.619 0.619 $ +0.628 0.628 0.628 $ +0.637 0.637 0.637 $ +0.645 0.645 0.645 $ +0.654 0.654 0.654 $ +0.663 0.663 0.663 $ +0.671 0.671 0.671 $ +0.68 0.68 0.68 $ +0.688 0.688 0.688 $ +0.697 0.697 0.697 $ +0.706 0.706 0.706 $ +0.714 0.714 0.714 $ +0.723 0.723 0.723 $ +0.732 0.732 0.732 $ +0.74 0.74 0.74 $ +0.749 0.749 0.749 $ +0.758 0.758 0.758 $ +0.766 0.766 0.766 $ +0.775 0.775 0.775 $ +0.784 0.784 0.784 $ +0.792 0.792 0.792 $ +0.801 0.801 0.801 $ +0.81 0.81 0.81 $ +0.818 0.818 0.818 $ +0.827 0.827 0.827 $ +0.836 0.836 0.836 $ +0.844 0.844 0.844 $ +0.853 0.853 0.853 $ +0.862 0.862 0.862 $ +0.87 0.87 0.87 $ +0.879 0.879 0.879 $ +0.888 0.888 0.888 $ +0.896 0.896 0.896 $ +0.905 0.905 0.905 $ +0.913 0.913 0.913 $ +0.922 0.922 0.922 $ +0.931 0.931 0.931 $ +0.939 0.939 0.939 $ +0.948 0.948 0.948 $ +0.957 0.957 0.957 $ +0.965 0.965 0.965 $ +0.974 0.974 0.974 $ +0.983 0.983 0.983 $ +0.991 0.991 0.991 $ +1 1 1 $ +406.645 540.058 23.8358 0 radial +popc +newpath +newpath +401.536 541.99 m +401.536 541.99 399.555 541.45 399.376 541.27 c +399.195 541.09 397.935 538.569 397.935 538.569 c +397.935 538.569 402.976 535.328 402.976 535.328 c +402.976 535.328 407.118 532.987 410.539 532.627 c +413.96 532.267 417.021 531.907 417.021 531.907 c +417.021 531.907 417.201 535.148 416.66 535.148 c +416.12 535.148 410.358 536.048 410.179 536.048 c +409.999 536.048 408.018 535.868 404.417 538.749 c +400.816 541.63 402.256 541.27 402.076 541.27 c +closepath +0.596 0.596 0.596 rgb +F +[15.1246 0 0 -7.74233 430.975 533.257] ellipse +pushc +eoclip newpath +50 gradient +0.576 0.576 0.576 $ +0.585 0.585 0.585 $ +0.593 0.593 0.593 $ +0.602 0.602 0.602 $ +0.611 0.611 0.611 $ +0.619 0.619 0.619 $ +0.628 0.628 0.628 $ +0.637 0.637 0.637 $ +0.645 0.645 0.645 $ +0.654 0.654 0.654 $ +0.663 0.663 0.663 $ +0.671 0.671 0.671 $ +0.68 0.68 0.68 $ +0.688 0.688 0.688 $ +0.697 0.697 0.697 $ +0.706 0.706 0.706 $ +0.714 0.714 0.714 $ +0.723 0.723 0.723 $ +0.732 0.732 0.732 $ +0.74 0.74 0.74 $ +0.749 0.749 0.749 $ +0.758 0.758 0.758 $ +0.766 0.766 0.766 $ +0.775 0.775 0.775 $ +0.784 0.784 0.784 $ +0.792 0.792 0.792 $ +0.801 0.801 0.801 $ +0.81 0.81 0.81 $ +0.818 0.818 0.818 $ +0.827 0.827 0.827 $ +0.836 0.836 0.836 $ +0.844 0.844 0.844 $ +0.853 0.853 0.853 $ +0.862 0.862 0.862 $ +0.87 0.87 0.87 $ +0.879 0.879 0.879 $ +0.888 0.888 0.888 $ +0.896 0.896 0.896 $ +0.905 0.905 0.905 $ +0.913 0.913 0.913 $ +0.922 0.922 0.922 $ +0.931 0.931 0.931 $ +0.939 0.939 0.939 $ +0.948 0.948 0.948 $ +0.957 0.957 0.957 $ +0.965 0.965 0.965 $ +0.974 0.974 0.974 $ +0.983 0.983 0.983 $ +0.991 0.991 0.991 $ +1 1 1 $ +424.493 535.58 23.8359 0 radial +popc +newpath +newpath +443.015 533.954 m +443.015 533.954 452.018 532.874 461.742 533.954 c +471.464 535.035 479.026 538.996 479.026 538.996 c +479.026 538.996 480.467 531.434 480.467 531.434 c +480.467 531.434 469.664 527.473 462.101 526.392 c +454.539 525.312 437.974 526.032 437.974 526.032 c +437.974 526.032 435.093 526.392 435.093 526.392 c +435.093 526.392 442.295 533.954 442.295 533.954 c +closepath +pushc +eoclip newpath +50 gradient +0.576 0.576 0.576 $ +0.585 0.585 0.585 $ +0.593 0.593 0.593 $ +0.602 0.602 0.602 $ +0.611 0.611 0.611 $ +0.619 0.619 0.619 $ +0.628 0.628 0.628 $ +0.637 0.637 0.637 $ +0.645 0.645 0.645 $ +0.654 0.654 0.654 $ +0.663 0.663 0.663 $ +0.671 0.671 0.671 $ +0.68 0.68 0.68 $ +0.688 0.688 0.688 $ +0.697 0.697 0.697 $ +0.706 0.706 0.706 $ +0.714 0.714 0.714 $ +0.723 0.723 0.723 $ +0.732 0.732 0.732 $ +0.74 0.74 0.74 $ +0.749 0.749 0.749 $ +0.758 0.758 0.758 $ +0.766 0.766 0.766 $ +0.775 0.775 0.775 $ +0.784 0.784 0.784 $ +0.792 0.792 0.792 $ +0.801 0.801 0.801 $ +0.81 0.81 0.81 $ +0.818 0.818 0.818 $ +0.827 0.827 0.827 $ +0.836 0.836 0.836 $ +0.844 0.844 0.844 $ +0.853 0.853 0.853 $ +0.862 0.862 0.862 $ +0.87 0.87 0.87 $ +0.879 0.879 0.879 $ +0.888 0.888 0.888 $ +0.896 0.896 0.896 $ +0.905 0.905 0.905 $ +0.913 0.913 0.913 $ +0.922 0.922 0.922 $ +0.931 0.931 0.931 $ +0.939 0.939 0.939 $ +0.948 0.948 0.948 $ +0.957 0.957 0.957 $ +0.965 0.965 0.965 $ +0.974 0.974 0.974 $ +0.983 0.983 0.983 $ +0.991 0.991 0.991 $ +1 1 1 $ +455.432 543.354 460.128 521.439 axial +popc +newpath +newpath +432.212 546.558 m +435.814 544.758 l +0.768 0.768 0.768 rgb +1 w +0 j +0 J +[] 0 d +S +newpath +435.093 548.359 m +439.055 545.838 l +S +newpath +444.456 544.037 m +449.497 542.598 l +S +newpath +448.057 545.838 m +451.298 544.758 l +S +newpath +428.972 525.492 m +429.331 525.852 432.572 531.794 432.572 531.794 c +432.572 531.794 443.015 530.353 443.015 530.353 c +443.015 530.353 451.838 530.173 452.558 529.813 c +453.279 529.453 468.943 532.154 469.304 532.515 c +469.664 532.874 479.387 537.195 479.387 537.195 c +479.387 537.195 481.547 531.254 481.187 531.254 c +480.827 531.254 480.467 529.813 465.342 527.112 c +450.218 524.412 450.938 525.132 442.656 525.492 c +434.373 525.852 428.611 525.672 428.611 525.672 c +closepath +0.596 0.596 0.596 rgb +F +newpath +420.058 538.366 m +420.058 538.366 418.078 537.826 417.898 537.646 c +417.718 537.465 416.457 534.945 416.457 534.945 c +416.457 534.945 421.499 531.704 421.499 531.704 c +421.499 531.704 425.64 529.363 429.061 529.003 c +432.483 528.643 433.563 529.543 433.563 529.543 c +433.563 529.543 434.103 531.884 433.563 531.884 c +433.023 531.884 428.881 532.424 428.701 532.424 c +428.521 532.424 426.541 532.244 422.94 535.125 c +419.338 538.006 420.779 537.646 420.599 537.646 c +closepath +F +newpath +426.451 622.542 m +426.451 622.542 433.112 618.58 433.833 617.32 c +434.553 616.06 439.414 613.179 442.295 613.179 c +445.176 613.179 451.298 615.7 451.298 615.7 c +451.298 615.7 461.742 619.301 461.742 619.301 c +461.742 619.301 455.799 618.761 450.038 616.96 c +444.276 615.159 444.816 615.339 441.935 615.339 c +439.055 615.339 434.013 619.301 433.653 619.301 c +433.293 619.301 426.451 622.542 426.451 622.542 c +closepath +pushc +eoclip newpath +50 gradient +0.616 0 0 $ +0.611 0 0 $ +0.606 0 0 $ +0.602 0 0 $ +0.597 0 0 $ +0.592 0 0 $ +0.587 0 0 $ +0.582 0 0 $ +0.578 0 0 $ +0.573 0 0 $ +0.568 0 0 $ +0.563 0 0 $ +0.558 0 0 $ +0.554 0 0 $ +0.549 0 0 $ +0.544 0 0 $ +0.539 0 0 $ +0.534 0 0 $ +0.53 0 0 $ +0.525 0 0 $ +0.52 0 0 $ +0.515 0 0 $ +0.51 0 0 $ +0.506 0 0 $ +0.501 0 0 $ +0.496 0 0 $ +0.491 0 0 $ +0.486 0 0 $ +0.482 0 0 $ +0.477 0 0 $ +0.472 0 0 $ +0.467 0 0 $ +0.463 0 0 $ +0.458 0 0 $ +0.455 0 0 $ +0.456 0 0 $ +0.457 0 0 $ +0.457 0 0 $ +0.458 0 0 $ +0.459 0 0 $ +0.459 0 0 $ +0.46 0 0 $ +0.46 0 0 $ +0.461 0 0 $ +0.462 0 0 $ +0.462 0 0 $ +0.463 0 0 $ +0.464 0 0 $ +0.464 0 0 $ +0.465 0 0 $ +444.096 617.86 18.256 0 radial +popc +newpath +newpath +246.446 791.099 m +246.263 653.969 l +257.252 653.969 l +266.043 663.649 l +266.043 779.806 l +259.45 790.292 l +246.263 790.292 l +closepath +1 1 1 rgb +F +newpath +338.281 563.853 m +261.027 609.375 l +271.99 609.375 l +286.201 606.162 l +351.486 567.602 l +350.801 564.121 l +337.645 564.121 l +closepath +F +newpath +71.1751 794.729 m +71.1751 739.474 l +83.6291 739.474 l +87.292 751.573 l +86.9257 784.646 l +82.5302 794.326 l +71.5414 794.326 l +closepath +F +newpath +165.457 562.648 m +134.401 580.991 l +146.827 580.991 l +157.281 576.974 l +175.504 565.995 l +176.559 562.782 l +165.596 562.782 l +closepath +F +newpath +71.1751 705.191 m +71.1751 649.936 l +83.6291 649.936 l +87.292 662.036 l +86.9257 695.108 l +82.5302 704.788 l +71.5414 704.788 l +closepath +F +newpath +115.134 592.371 m +84.0782 610.714 l +96.5032 610.714 l +106.958 606.698 l +125.181 595.719 l +126.236 592.505 l +115.272 592.505 l +closepath +F +showpage +end +%%Trailer +cleartomark countdictstack exch sub { end } repeat restore +%%EOF diff --git a/share/examples/BSD_daemon/eps.patch b/share/examples/BSD_daemon/eps.patch new file mode 100644 index 000000000000..5f23cb69ef9c --- /dev/null +++ b/share/examples/BSD_daemon/eps.patch @@ -0,0 +1,35 @@ +--- beastie.eps.ref Sun Feb 11 22:46:59 2001 ++++ beastie.eps Sun Feb 11 23:01:43 2001 +@@ -19,6 +19,23 @@ + % + /$F2psDict 200 dict def + $F2psDict begin ++ ++% This controls the linethickness. I think large posters look better if ++% you use a value of 2. Small daemons looks better with a value of 1. ++/linethickness 1 def ++ ++% If you want to fiddle the colors: ++% col0 below is black (the lines) ++% col3 below is cyan (the shoelaces) ++% col7 below is white (eyes, shoes) ++% col13 below is green (the shooes) ++% col20 below is red (the daemon) ++% col31 below is gold (the pitchfork) ++ ++% This sets round ends on the lines, this looks better than sharp edges ++% but I have not found a way to convince xfig to do this. ++1 setlinecap ++ + $F2psDict /mtrx matrix put + /col-1 {0 setgray} bind def + /col0 {0.000 0.000 0.000 srgb} bind def +@@ -74,7 +91,7 @@ + /sh {show} bind def + /slc {setlinecap} bind def + /slj {setlinejoin} bind def +-/slw {setlinewidth} bind def ++/slw {linethickness mul setlinewidth} bind def + /srgb {setrgbcolor} bind def + /rot {rotate} bind def + /sc {scale} bind def diff --git a/share/examples/BSD_daemon/poster.sh b/share/examples/BSD_daemon/poster.sh new file mode 100644 index 000000000000..7465c243b769 --- /dev/null +++ b/share/examples/BSD_daemon/poster.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# "THE BEER-WARE LICENSE" (Revision 42): +# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you +# can do whatever you want with this stuff. If we meet some day, and you think +# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp +# ---------------------------------------------------------------------------- +# +# + +echo '%!' +echo '/beastie {' +cat beastie.eps +echo '} def' +cat FreeBSD.pfa + +echo ' + +/mm {25.4 div 72 mul} def +/FreeBSD findfont 120 scalefont setfont +/center 210 mm 2 div def +/top 297 mm def +/cshow { dup stringwidth pop 2 div neg 0 rmoveto show } def + +% "FreeBSD" across the top. +% 691 is "top - height of caps - (left - X("F"))" +center 691 moveto +(FreeBSD) cshow + +% Put beastie in the center +/sc 1.25 def +center 125 moveto +384 sc mul 2 div neg 0 rmoveto +gsave currentpoint translate sc sc scale beastie grestore + +% A box for the bottom text +gsave +10 30 moveto +210 mm 20 sub 0 rlineto +0 70 rlineto +210 mm 20 sub neg 0 rlineto +closepath +.7 .7 .9 setrgbcolor +fill +grestore + +% Bottom text +center 90 moveto +/FreeBSD findfont 50 scalefont setfont + +center 50 moveto +(https://www.FreeBSD.org) cshow + +% Do not forget Kirks copyright string. +10 105 moveto +/Times-Roman findfont 8 scalefont setfont +(BSD Daemon ) show +/Symbol findfont 8 scalefont setfont +(\343 ) show +/Times-Roman findfont 8 scalefont setfont +(Copyright 1988 by Marshall Kirk McKusick. All Rights Reserved.) show + +showpage +' diff --git a/share/examples/FreeBSD_version/FreeBSD_version.c b/share/examples/FreeBSD_version/FreeBSD_version.c new file mode 100644 index 000000000000..e3f5600a857f --- /dev/null +++ b/share/examples/FreeBSD_version/FreeBSD_version.c @@ -0,0 +1,20 @@ +#if __FreeBSD__ == 0 /* 1.0 did not define __FreeBSD__ */ +#define __FreeBSD_version 199401 +#elif __FreeBSD__ == 1 /* 1.1 defined it to be 1 */ +#define __FreeBSD_version 199405 +#else /* 2.0 and higher define it to be 2 */ +#include <osreldate.h> /* and this works */ +#endif +#include <stdio.h> +#include <unistd.h> + +int +main(void) { + printf("Compilation release date: %d\n", __FreeBSD_version); +#if __FreeBSD_version >= 199408 + printf("Execution environment release date: %d\n", getosreldate()); +#else + printf("Execution environment release date: can't tell\n"); +#endif + return (0); +} diff --git a/share/examples/FreeBSD_version/Makefile b/share/examples/FreeBSD_version/Makefile new file mode 100644 index 000000000000..13d60978e868 --- /dev/null +++ b/share/examples/FreeBSD_version/Makefile @@ -0,0 +1,9 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/${PROG} +PROG= FreeBSD_version +MAN= + +install: + +.include <bsd.prog.mk> diff --git a/share/examples/FreeBSD_version/README b/share/examples/FreeBSD_version/README new file mode 100644 index 000000000000..acf9eb1a963f --- /dev/null +++ b/share/examples/FreeBSD_version/README @@ -0,0 +1,4 @@ +This is an example of how to determine the version of FreeBSD that +a program was compiled on, and maybe running on (if 2.0 or better). + +This program is in the public domain. diff --git a/share/examples/Makefile b/share/examples/Makefile new file mode 100644 index 000000000000..0425e36c1cf5 --- /dev/null +++ b/share/examples/Makefile @@ -0,0 +1,419 @@ +# +# Doing a make install builds /usr/share/examples + +.include <src.opts.mk> + +PACKAGE=examples +FILESDIR= ${SHAREDIR}/examples + +LDIRS= BSD_daemon \ + FreeBSD_version \ + bootforth \ + csh \ + drivers \ + etc \ + find_interface \ + flua \ + indent \ + ipfw \ + jails \ + kld \ + libvgl \ + mdoc \ + netgraph \ + perfmon \ + ppi \ + ppp \ + printing \ + ses \ + scsi_target \ + sound \ + sunrpc \ + ypldap + + +SE_DIRS+= BSD_daemon +SE_BSD_DAEMON= \ + FreeBSD.pfa \ + README \ + beastie.eps \ + beastie.fig \ + eps.patch \ + poster.sh + +.if ${MACHINE_CPUARCH} == "amd64" +.if ${MK_BHYVE} != "no" +LDIRS+= bhyve +SE_DIRS+= bhyve +SE_BHYVEPACKAGE=bhyve +SE_BHYVE= vmrun.sh +PACKAGE_bhyve/vmrun.sh= bhyve +.endif +.endif + +SE_DIRS+= FreeBSD_version +SE_FREEBSD_VERSION= \ + FreeBSD_version.c \ + Makefile \ + README + +SE_DIRS+= bootforth +SE_BOOTFORTH_PACKAGE=bootloader +SE_BOOTFORTH= \ + README \ + boot.4th \ + frames.4th \ + loader.rc \ + menu.4th \ + menuconf.4th \ + screen.4th + +SE_DIRS+= csh +SE_CSHPACKAGE= csh +SE_CSH= dot.cshrc + +SE_DIRS+= drivers +SE_DRIVERS= \ + README \ + make_device_driver.sh \ + make_pseudo_driver.sh + +SE_DIRS+= etc +SE_ETC= \ + README.examples \ + bsd-style-copyright \ + make.conf + +SE_DIRS+= find_interface +SE_FIND_INTERFACE= \ + Makefile \ + README \ + find_interface.c + +SE_DIRS+= flua +SE_FLUA= libjail.lua + +SE_DIRS+= indent +SE_INDENT= indent.pro + +.if ${MK_IPFILTER} != "no" +SUBDIR+= ipfilter +.endif + +SE_DIRS+= ipfw +SE_IPFWPACKAGE= ipfw +SE_IPFW= change_rules.sh + +SE_DIRS+= jails +SE_JAILPACKAGE= jail +SE_JAILS= \ + README \ + VIMAGE \ + jail.xxx.conf \ + jib \ + jng \ + rc.conf.jails \ + rcjail.xxx.conf + +SE_DIRS+= kld +SE_KLD= Makefile + +SE_DIRS+= kld/cdev +SE_KLD_CDEV= \ + Makefile \ + README \ + +SE_DIRS+= kld/cdev/module +SE_KLD_CDEV_MODULE= \ + Makefile \ + cdev.c \ + cdev.h \ + cdevmod.c + +SE_DIRS+= kld/cdev/test +SE_KLD_CDEV_TEST= \ + Makefile \ + testcdev.c + +SE_DIRS+= kld/dyn_sysctl +SE_KLD_DYN_SYSCTL= \ + Makefile \ + README \ + dyn_sysctl.c + +SE_DIRS+= kld/firmware +SE_KLD_FIRMWARE= \ + Makefile \ + README + +SE_DIRS+= kld/firmware/fwconsumer +SE_KLD_FIRMWARE_FWCONSUMER= \ + Makefile \ + fw_consumer.c + +SE_DIRS+= kld/firmware/fwimage +SE_KLD_FIRMWARE_FWIMAGE= \ + Makefile \ + firmware.img.uu + +SE_DIRS+= kld/khelp +SE_KLD_KHELP= \ + Makefile \ + README \ + h_example.c + +SE_DIRS+= kld/syscall +SE_KLD_SYSCALL= Makefile + +SE_DIRS+= kld/syscall/module +SE_KLD_SYSCALL_MODULE= \ + Makefile \ + syscall.c + +SE_DIRS+= kld/syscall/test +SE_KLD_SYSCALL_TEST= \ + Makefile \ + call.c + +SE_DIRS+= libvgl +SE_LIBVGL= \ + Makefile \ + demo.c + +SE_DIRS+= mdoc +SE_MDOC= \ + POSIX-copyright \ + deshallify.sh \ + example.1 \ + example.3 \ + example.4 \ + example.9 + +SE_DIRS+= netgraph +SE_NETGRAPH= \ + ether.bridge \ + frame_relay \ + ngctl \ + raw \ + udp.tunnel \ + virtual.chain \ + virtual.lan \ + +SE_DIRS+= perfmon +SE_PERFMON= \ + Makefile \ + README \ + perfmon.c \ + +.if ${MK_PF} != "no" +SE_DIRS+= pf +.if ${MK_STAGING} == "no" +SE_PFPACKAGE= pf +SE_PF= \ + ackpri \ + faq-example1 \ + faq-example2 \ + faq-example3 \ + pf.conf \ + queue1 \ + queue2 \ + queue3 \ + queue4 \ + spamd +.endif +.endif + +SE_DIRS+= ppi +SE_PPI= \ + Makefile \ + ppilcd.c + +SE_DIRS+= ppp +SE_PPPPACKAGE= ppp +SE_PPP= \ + chap-auth \ + login-auth \ + ppp.conf.sample \ + ppp.conf.span-isp \ + ppp.conf.span-isp.working \ + ppp.linkdown.sample \ + ppp.linkdown.span-isp \ + ppp.linkdown.span-isp.working \ + ppp.linkup.sample \ + ppp.linkup.span-isp \ + ppp.linkup.span-isp.working \ + ppp.secret.sample \ + ppp.secret.span-isp \ + ppp.secret.span-isp.working + +SE_DIRS+= printing +SE_PRINTINGPACKAGE=lp +SE_PRINTING= \ + diablo-if-net \ + hpdf \ + hpif \ + hpof \ + hprf \ + hpvf \ + if-simple \ + if-simpleX \ + ifhp \ + make-ps-header \ + netprint \ + psdf \ + psdfX \ + psif \ + pstf \ + pstfX + +SE_DIRS+= ses +SE_SES= \ + Makefile \ + Makefile.inc + +SE_DIRS+= ses/getencstat +SE_SES_GETENCSTAT= \ + Makefile \ + getencstat.0 + +SE_DIRS+= ses/sesd +SE_SES_SESD= \ + Makefile \ + sesd.0 + +SE_DIRS+= ses/setencstat +SE_SES_SETENCSTAT= \ + Makefile \ + setencstat.0 + +SE_DIRS+= ses/setobjstat +SE_SES_SETOBJSTAT= \ + Makefile \ + setobjstat.0 + +SE_DIRS+= ses/srcs +SE_SES_SRCS= \ + chpmon.c \ + eltsub.c \ + eltsub.h \ + getencstat.c \ + getnobj.c \ + getobjmap.c \ + getobjstat.c \ + inienc.c \ + sesd.c \ + setencstat.c \ + setobjstat.c + +SE_DIRS+= scsi_target +SE_SCSI_TARGET= \ + Makefile \ + scsi_target.c \ + scsi_target.h \ + scsi_target.8 \ + scsi_cmds.c + +SE_DIRS+= sound +SE_SOUND= \ + basic.c \ + ossinit.h \ + ossmidi.h \ + midi.c \ + README + +SE_DIRS+= sunrpc +SE_SUNRPC= Makefile + +SE_DIRS+= sunrpc/dir +SE_SUNRPC_DIR= \ + Makefile \ + dir.x \ + dir_proc.c \ + rls.c + +SE_DIRS+= sunrpc/msg +SE_SUNRPC_MSG= \ + Makefile \ + msg.x \ + msg_proc.c \ + printmsg.c \ + rprintmsg.c + +SE_DIRS+= sunrpc/sort +SE_SUNRPC_SORT= \ + Makefile \ + rsort.c \ + sort.x \ + sort_proc.c + +.if ${MK_EFI} != "no" +LDIRS+= uefisign +SE_DIRS+= uefisign +SE_UEFISIGN= uefikeys +SE_UEFISIGNPACKAGE=efi-tools +.endif + +SE_DIRS+= ypldap +SE_YPLDAP= ypldap.conf +SE_YPLDAPPACKAGE=yp + +.if ${MK_HAST} != "no" +LDIRS+= hast +SE_HASTPACKAGE= hast +SE_DIRS+= hast +SE_HAST= ucarp.sh \ + ucarp_down.sh \ + ucarp_up.sh \ + vip-down.sh \ + vip-up.sh +.endif + +.if ${MK_USB} != "no" +LDIRS+= libusb20 +SE_DIRS+= libusb20 +SE_LIBUSB20= \ + Makefile \ + README \ + util.c \ + util.h \ + bulk.c \ + control.c +.endif + + +# Setup the FILES_GROUPS for all DIRS variables above. +# The variables are prefixed by 'SE_' to prevent variable collision in +# other parts of the system +.for d in ${SE_DIRS} +.for f in ${SE_${d:tu:C/\//_/g}} +SER_${d:tu:C/\//_/g}+= ${d}/${f} +.endfor +FILESGROUPS+= SER_${d:tu:C/\//_/g} +SER_${d:tu:C/\//_/g}DIR+= ${SHAREDIR}/examples/${d} +.if ${SE_${d:tu:C/\//_/g}PACKAGE:U} != "" +SER_${d:tu:C/\//_/g}PACKAGE= ${SE_${d:tu:C/\//_/g}PACKAGE} +.else +SER_${d:tu:C/\//_/g}PACKAGE= examples +.endif +.endfor + +BINDIR= ${SHAREDIR}/examples + +beforeinstall: copies +META_TARGETS+= copies + +copies: +.for i in ${LDIRS} + if [ -L ${DESTDIR}${BINDIR}/$i ]; then \ + rm -f ${DESTDIR}${BINDIR}/$i; \ + fi +.endfor + +SUBDIR+= smbfs + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + +SUBDIR_PARALLEL= + +.include <bsd.prog.mk> diff --git a/share/examples/Makefile.depend b/share/examples/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/bhyve/vmrun.sh b/share/examples/bhyve/vmrun.sh new file mode 100755 index 000000000000..323d8e22a041 --- /dev/null +++ b/share/examples/bhyve/vmrun.sh @@ -0,0 +1,410 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2013 NetApp, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +LOADER=/usr/sbin/bhyveload +BHYVECTL=/usr/sbin/bhyvectl +FBSDRUN=/usr/sbin/bhyve + +DEFAULT_MEMSIZE=512M +DEFAULT_CPUS=2 +DEFAULT_TAPDEV=tap0 +DEFAULT_CONSOLE=stdio + +DEFAULT_NIC=virtio-net +DEFAULT_DISK=virtio-blk +DEFAULT_VIRTIO_DISK="./diskdev" +DEFAULT_ISOFILE="./release.iso" + +DEFAULT_VNCHOST="127.0.0.1" +DEFAULT_VNCPORT=5900 +DEFAULT_VNCSIZE="w=1024,h=768" + +errmsg() { + echo "*** $1" +} + +usage() { + local msg=$1 + + echo "Usage: vmrun.sh [-aAEhiTuvw] [-c <CPUs>] [-C <console>]" \ + "[-d <disk file>]" + echo " [-e <name=value>] [-f <path of firmware>]" \ + "[-F <size>]" + echo " [-G [w][address:]port] [-H <directory>]" + echo " [-I <location of installation iso>] [-l <loader>]" + echo " [-L <VNC IP for UEFI framebuffer>]" + echo " [-m <memsize>]" \ + "[-n <network adapter emulation type>]" + echo " [-p <pcidev|bus/slot/func>]" + echo " [-P <port>] [-t <tapdev>] <vmname>" + echo "" + echo " -h: display this help message" + echo " -a: force memory mapped local APIC access" + echo " -A: use AHCI disk emulation instead of ${DEFAULT_DISK}" + echo " -c: number of virtual cpus (default: ${DEFAULT_CPUS})" + echo " -C: console device (default: ${DEFAULT_CONSOLE})" + echo " -d: virtio diskdev file (default: ${DEFAULT_VIRTIO_DISK})" + echo " -e: set FreeBSD loader environment variable" + echo " -E: Use UEFI mode" + echo " -f: Use a specific UEFI firmware" + echo " -F: Use a custom UEFI GOP framebuffer size" \ + "(default: ${DEFAULT_VNCSIZE})" + echo " -G: bind the GDB stub to the specified address" + echo " -H: host filesystem to export to the loader" + echo " -i: force boot of the Installation CDROM image" + echo " -I: Installation CDROM image location" \ + "(default: ${DEFAULT_ISOFILE})" + echo " -l: the OS loader to use (default: /boot/userboot.so)" + echo " -L: IP address for UEFI GOP VNC server" \ + "(default: ${DEFAULT_VNCHOST})" + echo " -m: memory size (default: ${DEFAULT_MEMSIZE})" + echo " -n: network adapter emulation type" \ + "(default: ${DEFAULT_NIC})" + echo " -p: pass-through a host PCI device (e.g ppt0 or" \ + "bus/slot/func)" + echo " -P: UEFI GOP VNC port (default: ${DEFAULT_VNCPORT})" + echo " -t: tap device for virtio-net (default: $DEFAULT_TAPDEV)" + echo " -T: Enable tablet device (for UEFI GOP)" + echo " -u: RTC keeps UTC time" + echo " -v: Wait for VNC client connection before booting VM" + echo " -w: ignore unimplemented MSRs" + echo "" + [ -n "$msg" ] && errmsg "$msg" + exit 1 +} + +if [ `id -u` -ne 0 ]; then + errmsg "This script must be executed with superuser privileges" + exit 1 +fi + +kldstat -n vmm > /dev/null 2>&1 +if [ $? -ne 0 ]; then + errmsg "vmm.ko is not loaded" + exit 1 +fi + +force_install=0 +isofile=${DEFAULT_ISOFILE} +memsize=${DEFAULT_MEMSIZE} +console=${DEFAULT_CONSOLE} +cpus=${DEFAULT_CPUS} +nic=${DEFAULT_NIC} +tap_total=0 +disk_total=0 +disk_emulation=${DEFAULT_DISK} +loader_opt="" +bhyverun_opt="-H -A -P" +pass_total=0 + +# EFI-specific options +efi_mode=0 +efi_firmware="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd" +vncwait="" +vnchost=${DEFAULT_VNCHOST} +vncport=${DEFAULT_VNCPORT} +vncsize=${DEFAULT_VNCSIZE} +tablet="" + +while getopts aAc:C:d:e:Ef:F:G:hH:iI:l:L:m:n:p:P:t:Tuvw c ; do + case $c in + a) + bhyverun_opt="${bhyverun_opt} -a" + ;; + A) + disk_emulation="ahci-hd" + ;; + c) + cpus=${OPTARG} + ;; + C) + console=${OPTARG} + ;; + d) + disk_dev=${OPTARG%%,*} + disk_opts=${OPTARG#${disk_dev}} + eval "disk_dev${disk_total}=\"${disk_dev}\"" + eval "disk_opts${disk_total}=\"${disk_opts}\"" + disk_total=$(($disk_total + 1)) + ;; + e) + loader_opt="${loader_opt} -e ${OPTARG}" + ;; + E) + efi_mode=1 + ;; + f) + efi_firmware="${OPTARG}" + ;; + F) + vncsize="${OPTARG}" + ;; + G) + bhyverun_opt="${bhyverun_opt} -G ${OPTARG}" + ;; + H) + host_base=`realpath ${OPTARG}` + ;; + i) + force_install=1 + ;; + I) + isofile=${OPTARG} + ;; + l) + loader_opt="${loader_opt} -l ${OPTARG}" + ;; + L) + vnchost="${OPTARG}" + ;; + m) + memsize=${OPTARG} + ;; + n) + nic=${OPTARG} + ;; + p) + eval "pass_dev${pass_total}=\"${OPTARG}\"" + pass_total=$(($pass_total + 1)) + ;; + P) + vncport="${OPTARG}" + ;; + t) + eval "tap_dev${tap_total}=\"${OPTARG}\"" + tap_total=$(($tap_total + 1)) + ;; + T) + tablet="-s 30,xhci,tablet" + ;; + u) + bhyverun_opt="${bhyverun_opt} -u" + ;; + v) + vncwait=",wait" + ;; + w) + bhyverun_opt="${bhyverun_opt} -w" + ;; + *) + usage + ;; + esac +done + +if [ $tap_total -eq 0 ] ; then + tap_total=1 + tap_dev0="${DEFAULT_TAPDEV}" +fi +if [ $disk_total -eq 0 ] ; then + disk_total=1 + disk_dev0="${DEFAULT_VIRTIO_DISK}" + +fi + +shift $((${OPTIND} - 1)) + +if [ $# -ne 1 ]; then + usage "virtual machine name not specified" +fi + +vmname="$1" +if [ -n "${host_base}" ]; then + loader_opt="${loader_opt} -h ${host_base}" +fi + +# If PCI passthru devices are configured then guest memory must be wired +if [ ${pass_total} -gt 0 ]; then + loader_opt="${loader_opt} -S" + bhyverun_opt="${bhyverun_opt} -S" +fi + +if [ ${efi_mode} -gt 0 ]; then + if [ ! -f ${efi_firmware} ]; then + echo "Error: EFI Firmware ${efi_firmware} doesn't exist." \ + "Try: pkg install edk2-bhyve" + exit 1 + fi +fi + +make_and_check_diskdev() +{ + local virtio_diskdev="$1" + # Create the virtio diskdev file if needed + if [ ! -e ${virtio_diskdev} ]; then + echo "virtio disk device file \"${virtio_diskdev}\" does not exist." + echo "Creating it ..." + truncate -s 8G ${virtio_diskdev} > /dev/null + fi + + if [ ! -r ${virtio_diskdev} ]; then + echo "virtio disk device file \"${virtio_diskdev}\" is not readable" + exit 1 + fi + + if [ ! -w ${virtio_diskdev} ]; then + echo "virtio disk device file \"${virtio_diskdev}\" is not writable" + exit 1 + fi +} + +echo "Launching virtual machine \"$vmname\" ..." + +first_diskdev="$disk_dev0" + +${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 + +while [ 1 ]; do + + file -s ${first_diskdev} | grep "boot sector" > /dev/null + rc=$? + if [ $rc -ne 0 ]; then + file -s ${first_diskdev} | \ + grep ": Unix Fast File sys" > /dev/null + rc=$? + fi + if [ $rc -ne 0 ]; then + need_install=1 + else + need_install=0 + fi + + if [ $force_install -eq 1 -o $need_install -eq 1 ]; then + if [ ! -r ${isofile} ]; then + echo -n "Installation CDROM image \"${isofile}\" " + echo "is not readable" + exit 1 + fi + BOOTDISKS="-d ${isofile}" + installer_opt="-s 31:0,ahci-cd,${isofile}" + else + BOOTDISKS="" + i=0 + while [ $i -lt $disk_total ] ; do + eval "disk=\$disk_dev${i}" + if [ -r ${disk} ] ; then + BOOTDISKS="$BOOTDISKS -d ${disk} " + fi + i=$(($i + 1)) + done + installer_opt="" + fi + + if [ ${efi_mode} -eq 0 ]; then + ${LOADER} -c ${console} -m ${memsize} ${BOOTDISKS} \ + ${loader_opt} ${vmname} + bhyve_exit=$? + if [ $bhyve_exit -ne 0 ]; then + break + fi + fi + + # + # Build up args for additional tap and disk devices now. + # + nextslot=2 # slot 0 is hostbridge, slot 1 is lpc + devargs="" # accumulate disk/tap args here + i=0 + while [ $i -lt $tap_total ] ; do + eval "tapname=\$tap_dev${i}" + devargs="$devargs -s $nextslot:0,${nic},${tapname} " + nextslot=$(($nextslot + 1)) + i=$(($i + 1)) + done + + i=0 + while [ $i -lt $disk_total ] ; do + eval "disk=\$disk_dev${i}" + eval "opts=\$disk_opts${i}" + make_and_check_diskdev "${disk}" + devargs="$devargs -s $nextslot:0,$disk_emulation,${disk}${opts} " + nextslot=$(($nextslot + 1)) + i=$(($i + 1)) + done + + i=0 + while [ $i -lt $pass_total ] ; do + eval "pass=\$pass_dev${i}" + bsfform="$(echo "${pass}" | grep "^[0-9]\+/[0-9]\+/[0-9]\+$")" + if [ -z "${bsfform}" ]; then + bsf="$(pciconf -l "${pass}" 2>/dev/null)" + if [ $? -ne 0 ]; then + errmsg "${pass} is not a host PCI device" + exit 1 + fi + bsf="$(echo "${bsf}" | awk -F: '{print $2"/"$3"/"$4}')" + else + bsf="${pass}" + fi + devargs="$devargs -s $nextslot:0,passthru,${bsf} " + nextslot=$(($nextslot + 1)) + i=$(($i + 1)) + done + + efiargs="" + if [ ${efi_mode} -gt 0 ]; then + efiargs="-s 29,fbuf,tcp=${vnchost}:${vncport}," + efiargs="${efiargs}${vncsize}${vncwait}" + efiargs="${efiargs} -l bootrom,${efi_firmware}" + efiargs="${efiargs} ${tablet}" + fi + + ${FBSDRUN} -c ${cpus} -m ${memsize} ${bhyverun_opt} \ + -s 0:0,hostbridge \ + -s 1:0,lpc \ + ${efiargs} \ + ${devargs} \ + -l com1,${console} \ + ${installer_opt} \ + ${vmname} + + bhyve_exit=$? + # bhyve returns the following status codes: + # 0 - VM has been reset + # 1 - VM has been powered off + # 2 - VM has been halted + # 3 - VM generated a triple fault + # all other non-zero status codes are errors + # + if [ $bhyve_exit -ne 0 ]; then + break + fi +done + + +case $bhyve_exit in + 0|1|2) + # Cleanup /dev/vmm entry when bhyve did not exit + # due to an error. + ${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1 + ;; +esac + +exit $bhyve_exit diff --git a/share/examples/bootforth/README b/share/examples/bootforth/README new file mode 100644 index 000000000000..69db86ee8806 --- /dev/null +++ b/share/examples/bootforth/README @@ -0,0 +1,33 @@ +Here you can find some simple examples how to use BootFORTH (part of the +new bootloader) together with terminal emulation code (available when +compiling /stand/i386/libi386 with -DTERM_EMU). + +Normally, you can place the files in /boot as they are here, and they will be +automatically loaded by /boot/loader. You must choose between boot.4th or +loader.rc, though. Copy one or the other, but not both. Also, menu.4th is +only used by boot.4th, and menuconf.4th is only used by loader.rc, so you +don't need to copy both files. + +The files are: + +boot.4th example of file which is always loaded by /boot/loader, if + present in /boot/ +loader.rc example of file which is always loader by /boot/loader, if + present in /boot/ +screen.4th helpful words for screen manipulation. +frames.4th basic frame drawing primitives. Requires screen.4th. +menu.4th example of simple startup menu. +menuconf.4th another example of simples startup menu. + +You're encouraged to add more features to these files - I'm not a Forth +hacker, unfortunately... + +Andrzej Bialecki +<abial@freebsd.org> + +If you use loader.rc/menuconf.4th, be sure to create /boot/stable.conf and +/boot/current.conf, like described in loader.conf(5), with appropriate +configuration to distinguish one from the other. + +Daniel C. Sobral +<dcs@freebsd.org> diff --git a/share/examples/bootforth/boot.4th b/share/examples/bootforth/boot.4th new file mode 100644 index 000000000000..3f75424e46c5 --- /dev/null +++ b/share/examples/bootforth/boot.4th @@ -0,0 +1,21 @@ +\ Example of the file which is automatically loaded by /boot/loader +\ on startup. + +\ Load the screen manipulation words + +cr .( Loading Forth extensions:) + +cr .( - screen.4th...) +s" /boot/screen.4th" O_RDONLY fopen dup fload fclose + +\ Load frame support +cr .( - frames.4th...) +s" /boot/frames.4th" O_RDONLY fopen dup fload fclose + +\ Load our little menu +cr .( - menu.4th...) +s" /boot/menu.4th" O_RDONLY fopen dup fload fclose + +\ Show it +cr +main_menu diff --git a/share/examples/bootforth/frames.4th b/share/examples/bootforth/frames.4th new file mode 100644 index 000000000000..0adcf9ef648b --- /dev/null +++ b/share/examples/bootforth/frames.4th @@ -0,0 +1,88 @@ +\ Words implementing frame drawing +\ XXX Filled boxes are left as an exercise for the reader... ;-/ + +marker task-frames.4th + +variable h_el +variable v_el +variable lt_el +variable lb_el +variable rt_el +variable rb_el +variable fill + +\ Single frames +196 constant sh_el +179 constant sv_el +218 constant slt_el +192 constant slb_el +191 constant srt_el +217 constant srb_el +\ Double frames +205 constant dh_el +186 constant dv_el +201 constant dlt_el +200 constant dlb_el +187 constant drt_el +188 constant drb_el +\ Fillings +0 constant fill_none +32 constant fill_blank +176 constant fill_dark +177 constant fill_med +178 constant fill_bright + +: hline ( len x y -- ) \ Draw horizontal single line + at-xy \ move cursor + 0 do + h_el @ emit + loop +; + +: f_single ( -- ) \ set frames to single + sh_el h_el ! + sv_el v_el ! + slt_el lt_el ! + slb_el lb_el ! + srt_el rt_el ! + srb_el rb_el ! +; + +: f_double ( -- ) \ set frames to double + dh_el h_el ! + dv_el v_el ! + dlt_el lt_el ! + dlb_el lb_el ! + drt_el rt_el ! + drb_el rb_el ! +; + +: vline ( len x y -- ) \ Draw vertical single line + 2dup 4 pick + 0 do + at-xy + v_el @ emit + 1+ + 2dup + loop + 2drop 2drop drop +; + +: box ( w h x y -- ) \ Draw a box + 2dup 1+ 4 pick 1- -rot + vline \ Draw left vert line + 2dup 1+ swap 5 pick + swap 4 pick 1- -rot + vline \ Draw right vert line + 2dup swap 1+ swap 5 pick 1- -rot + hline \ Draw top horiz line + 2dup swap 1+ swap 4 pick + 5 pick 1- -rot + hline \ Draw bottom horiz line + 2dup at-xy lt_el @ emit \ Draw left-top corner + 2dup 4 pick + at-xy lb_el @ emit \ Draw left bottom corner + 2dup swap 5 pick + swap at-xy rt_el @ emit \ Draw right top corner + 2 pick + swap 3 pick + swap at-xy rb_el @ emit + 2drop +; + +f_single +fill_none fill ! diff --git a/share/examples/bootforth/loader.rc b/share/examples/bootforth/loader.rc new file mode 100644 index 000000000000..e8aa549f5905 --- /dev/null +++ b/share/examples/bootforth/loader.rc @@ -0,0 +1,33 @@ +\ Example of the file which is automatically loaded by /boot/loader +\ on startup. + +cr .( Loading Forth extensions:) + +\ Load configuration file words + +cr .( - loader.4th...) + +include /boot/loader.4th + +\ Load the screen manipulation words + +cr .( - screen.4th...) +s" /boot/screen.4th" O_RDONLY fopen dup fload fclose + +\ Load frame support +cr .( - frames.4th...) +s" /boot/frames.4th" O_RDONLY fopen dup fload fclose + +\ Load our little menu +cr .( - menuconf.4th...) +s" /boot/menuconf.4th" O_RDONLY fopen dup fload fclose + +\ Initialize loader.4th stuff + +cr cr .( Initializing loader.4th...) +initialize drop + +\ Show the menu +cr +main_menu + diff --git a/share/examples/bootforth/menu.4th b/share/examples/bootforth/menu.4th new file mode 100644 index 000000000000..3462ea9fc5a9 --- /dev/null +++ b/share/examples/bootforth/menu.4th @@ -0,0 +1,98 @@ +\ Simple greeting screen, presenting basic options. +\ XXX This is far too trivial - I don't have time now to think +\ XXX about something more fancy... :-/ + +: title + f_single + 60 11 10 4 box + 29 4 at-xy 15 fg 7 bg + ." Welcome to BootFORTH!" + me +; + +: menu + 2 fg + 20 7 at-xy + ." 1. Start FreeBSD /kernel." + 20 8 at-xy + ." 2. Interact with BootFORTH." + 20 9 at-xy + ." 3. Reboot." + me +; + +: tkey ( d -- flag | char ) + seconds + + begin 1 while + dup seconds u< if + drop + -1 + exit + then + key? if + drop + key + exit + then + repeat +; + +: prompt + 14 fg + 20 11 at-xy + ." Enter your option (1,2,3): " + 10 tkey + dup 32 = if + drop key + then + dup 0< if + drop 49 + then + dup emit + me +; + +: help_text + 10 18 at-xy ." * Choose 1 if you just want to run FreeBSD." + 10 19 at-xy ." * Choose 2 if you want to use bootloader facilities." + 12 20 at-xy ." See '?' for available commands, and 'words' for" + 12 21 at-xy ." complete list of Forth words." + 10 22 at-xy ." * Choose 3 in order to warm boot your machine." +; + +: (boot) 0 boot ; +: (reboot) 0 reboot ; + +: main_menu + begin 1 while + clear + f_double + 79 23 1 1 box + title + menu + help_text + prompt + cr cr cr + dup 49 = if + drop + 1 25 at-xy cr + ." Loading kernel. Please wait..." cr + ['] (boot) catch abort" Error booting" + then + dup 50 = if + drop + 1 25 at-xy cr + exit + then + dup 51 = if + drop + 1 25 at-xy cr + ['] (reboot) catch abort" Error rebooting" + then + 20 12 at-xy + ." Key " emit ." is not a valid option!" + 20 13 at-xy + ." Press any key to continue..." + key drop + repeat +; diff --git a/share/examples/bootforth/menuconf.4th b/share/examples/bootforth/menuconf.4th new file mode 100644 index 000000000000..df53e812aabc --- /dev/null +++ b/share/examples/bootforth/menuconf.4th @@ -0,0 +1,109 @@ +\ Simple greeting screen, presenting basic options. +\ XXX This is far too trivial - I don't have time now to think +\ XXX about something more fancy... :-/ + +: title + f_single + 60 11 10 4 box + 29 4 at-xy 15 fg 7 bg + ." Welcome to BootFORTH!" + me +; + +: menu + 2 fg + 20 7 at-xy + ." 1. Start FreeBSD with /boot/stable.conf." + 20 8 at-xy + ." 2. Start FreeBSD with /boot/current.conf." + 20 9 at-xy + ." 3. Start FreeBSD with standard configuration. " + 20 10 at-xy + ." 4. Reboot." + me +; + +: tkey ( d -- flag | char ) + seconds + + begin 1 while + dup seconds u< if + drop + -1 + exit + then + key? if + drop + key + exit + then + repeat +; + +: prompt + 14 fg + 20 12 at-xy + ." Enter your option (1,2,3,4): " + 10 tkey + dup 32 = if + drop key + then + dup 0< if + drop 51 + then + dup emit + me +; + +: help_text + 10 18 at-xy ." * Choose 1 or 2 to run special configuration file." + 10 19 at-xy ." * Choose 3 to proceed with standard bootstrapping." + 12 20 at-xy ." See '?' for available commands, and 'words' for" + 12 21 at-xy ." complete list of Forth words." + 10 22 at-xy ." * Choose 4 in order to warm boot your machine." +; + +: (reboot) 0 reboot ; + +: main_menu + begin 1 while + clear + f_double + 79 23 1 1 box + title + menu + help_text + prompt + cr cr cr + dup 49 = if + drop + 1 25 at-xy cr + ." Loading /boot/stable.conf. Please wait..." cr + s" /boot/stable.conf" read-conf + 0 boot-conf exit + then + dup 50 = if + drop + 1 25 at-xy cr + ." Loading /boot/current.conf. Please wait..." cr + s" /boot/current.conf" read-conf + 0 boot-conf exit + then + dup 51 = if + drop + 1 25 at-xy cr + ." Proceeding with standard boot. Please wait..." cr + 0 boot-conf exit + then + dup 52 = if + drop + 1 25 at-xy cr + ['] (reboot) catch abort" Error rebooting" + then + 20 12 at-xy + ." Key " emit ." is not a valid option!" + 20 13 at-xy + ." Press any key to continue..." + key drop + repeat +; + diff --git a/share/examples/bootforth/screen.4th b/share/examples/bootforth/screen.4th new file mode 100644 index 000000000000..8bd873f48884 --- /dev/null +++ b/share/examples/bootforth/screen.4th @@ -0,0 +1,35 @@ +\ Screen manipulation related words. + +marker task-screen.4th + +: escc ( -- ) \ emit Esc-[ + 91 27 emit emit +; + +: ho ( -- ) \ Home cursor + escc 72 emit \ Esc-[H +; + +: cld ( -- ) \ Clear from current position to end of display + escc 74 emit \ Esc-[J +; + +: clear ( -- ) \ clear screen + ho cld +; + +: at-xy ( x y -- ) \ move cursor to x rows, y cols (1-based coords) + escc .# 59 emit .# 72 emit \ Esc-[%d;%dH +; + +: fg ( x -- ) \ Set foreground color + escc 3 .# .# 109 emit \ Esc-[3%dm +; + +: bg ( x -- ) \ Set background color + escc 4 .# .# 109 emit \ Esc-[4%dm +; + +: me ( -- ) \ Mode end (clear attributes) + escc 109 emit +; diff --git a/share/examples/csh/dot.cshrc b/share/examples/csh/dot.cshrc new file mode 100644 index 000000000000..5cda009dbd96 --- /dev/null +++ b/share/examples/csh/dot.cshrc @@ -0,0 +1,139 @@ +# Here are some example (t)csh options and configurations that you may find interesting +# +# + +# Sets SSH_AUTH_SOCK to the user's ssh-agent socket path if running +# +# This has a couple caveats, the most notable being that if a user +# has multiple ssh-agent(1) processes running, this will very likely +# set SSH_AUTH_SOCK to point to the wrong file/domain socket. +if (${?SSH_AUTH_SOCK} != "1") then + setenv SSH_AUTH_SOCK `sockstat -u | awk '/^${USER}.+ ssh-agent/ { print $6 }'` +endif + +# Change only root's prompt +if (`id -g` == 0) then + set prompt="root@%m# " +endif + +# This maps the "Delete" key to do the right thing +# Pressing CTRL-v followed by the key of interest will print the shell's +# mapping for the key +bindkey "^[[3~" delete-char-or-list-or-eof + +# Make the Ins key work +bindkey "\e[2~" overwrite-mode + +# Some common completions +complete cd 'p/1/d/' +complete chown 'p/1/u/' +complete dd 'c/[io]f=/f/ n/*/"(if of ibs obs bs skip seek count)"/=' +complete find 'n/-fstype/"(nfs 4.2)"/' 'n/-name/f/' \ + 'n/-type/(c b d f p l s)/' \ + 'n/-user/u/ n/-group/g/' \ + 'n/-exec/c/' 'n/-ok/c/' \ + 'n/-cpio/f/' \ + 'n/-ncpio/f/' \ + 'n/-newer/f/' \ + 'c/-/(fstype name perm prune type user nouser group nogroup size inum atime mtime ctime exec \ + ok print ls cpio ncpio newer xdev depth daystart follow maxdepth mindepth noleaf version \ + anewer cnewer amin cmin mmin true false uid gid ilname iname ipath iregex links lname empty path \ + regex used xtype fprint fprint0 fprintf print0 printf not a and o or)/' \ + 'n/*/d/' +complete fg 'c/%/j/' +complete gpart 'p/1/(add backup bootcode commit create delete destroy modify recover resize restore set show undo unset)/' \ + 'n/add/x:-t type [-a alignment] [-b start] [-s size] [-i index] [-l label] -f flags geom/' \ + 'n/backup/x:geom/' \ + 'n/bootcode/x:[-b bootcode] [-p partcode -i index] [-f flags] geom/' \ + 'n/commit/x:geom/' \ + 'n/create/x:-s scheme [-n entries] [-f flags] provider/' \ + 'n/delete/x:-i index [-f flags] geom/' \ + 'n/destroy/x:[-F] [-f flags] geom/' \ + 'n/modify/x:-i index [-l label] [-t type] [-f flags] geom/' \ + 'n/recover/x:[-f flags] geom/' \ + 'n/resize/x:-i index [-a alignment] [-s size] [-f flags] geom/' \ + 'n/restore/x:[-lF] [-f flags] provider [...]/' \ + 'n/set/x:-a attrib -i index [-f flags] geom/' \ + 'n/show/x:[-l | -r] [-p] [geom ...]/' \ + 'n/undo/x:geom/' \ + 'n/unset/x:-a attrib -i index [-f flags] geom/' +complete grep 'c/-*A/x:<#_lines_after>/' \ + 'c/-*B/x:<#_lines_before>/' \ + 'c/--/(extended-regexp fixed-regexp basic-regexp regexp file ignore-case word-regexp line-regexp \ + no-messages revert-match version help byte-offset line-number with-filename no-filename quiet silent \ + text directories recursive files-without-match files-with-matches count before-context after-context \ + context binary unix-byte-offsets)/' \ + 'c/-/(A a B b C c d E e F f G H h i L l n q r s U u V v w x)/' \ + 'p/1/x:<limited_regular_expression>/ N/-*e/f/' \ + 'n/-*e/x:<limited_regular_expression>/' \ + 'n/-*f/f/' \ + 'n/*/f/' +complete ifconfig 'p@1@`ifconfig -l`@' \ + 'n/*/(range phase link netmask mtu vlandev vlan metric mediaopt down delete broadcast arp debug)/' \ + 'c/%/j/' \ + 'n/*/`ps -ax | awk '"'"'{print $1}'"'"'`/' +complete kill 'c/-/S/' 'c/%/j/' 'n/*/`ps -ax | awk '"'"'{print $1}'"'"'`/' +complete killall 'c/-/S/' 'c/%/j/' 'n/*/`ps -ax | awk '"'"'{print $5}'"'"'`/' +complete kldload 'n@*@`ls -1 /boot/modules/ /boot/kernel/ | awk -F/ \$NF\ \~\ \".ko\"\ \{sub\(\/\.ko\/,\"\",\$NF\)\;print\ \$NF\}`@' +complete kldunload 'n@*@`kldstat | awk \{sub\(\/\.ko\/,\"\",\$NF\)\;print\ \$NF\} | grep -v Name`@' +complete make 'p@1@`make -pn | sed -n -E "/^[#_.\/[:blank:]]+/d; /=/d; s/[[:blank:]]*:.*//gp;"`@' \ + 'n@-V@`make -ndv | & grep Global: | sed -E -e "s/^Global://" -e "s/ .*//" -e "/^[[:lower:]]/d" | sort | uniq`@' +complete man 'C/*/c/' +complete netstat 'n@-I@`ifconfig -l`@' +complete pkg_delete 'c/-/(i v D n p d f G x X r)/' 'n@*@`ls /var/db/pkg`@' +complete pkg_info 'c/-/(a b v p q Q c d D f g i I j k K r R m L s o G O x X e E l t V P)/' 'n@*@`\ls -1 /var/db/pkg | sed s%/var/db/pkg/%%`@' +complete ping 'p/1/$hosts/' +complete pkill 'c/-/S/' \ + 'n@*@`ps -axc -o command="" | sort | uniq`@' +complete portmaster 'c/--/(always-fetch check-depends check-port-dbdir clean-distfiles clean-packages delete-build-only \ + delete-packages force-config help index index-first index-only list-origins local-packagedir \ + no-confirm no-index-fetch no-term-title packages packages-build packages-if-newer packages-local \ + packages-only show-work update-if-newer version)/' \ + 'c/-/(a b B C d D e f F g G h H i l L m n o p r R s t u v w x)/' \ + 'n@*@`pkg_info -E \*`@' +complete rsync "c,*:/,F:/," \ + "c,*:,F:$HOME," \ + 'c/*@/$hosts/:/' +complete scp "c,*:/,F:/," \ + "c,*:,F:$HOME," \ + 'c/*@/$hosts/:/' +complete service 'c/-/(e l r v)/' 'p/1/`service -l`/' 'n/*/(start stop reload restart status rcvar describe extracommands onestart onestop oneextracommands)/' +complete svn 'C@file:///@`'"${HOME}/etc/tcsh/complete.d/svn"'`@@' \ + 'n@ls@(file:/// svn+ssh:// svn://)@@' \ + 'n@help@(add blame cat checkout cleanup commit copy delete export help import info list ls lock log merge mkdir move propdel \ + propedit propget proplist propset resolved revert status switch unlock update)@' 'p@1@(add blame cat checkout cleanup commit \ + copy delete export help import info list ls lock log merge mkdir move propdel propedit propget proplist propset resolved \ + revert status switch unlock update)@' +complete ssh 'p/1/$hosts/' \ + 'c/-/(l n)/' \ + 'n/-l/u/ N/-l/c/ n/-/c/ p/2/c/ p/*/f/' +complete sysctl 'n/*/`sysctl -Na`/' +complete tmux 'n/*/(attach detach has kill-server kill-session lsc lscm ls lockc locks new refresh rename showmsgs source start suspendc switchc)/' +complete which 'C/*/c/' + +if ( -f /etc/printcap ) then + set printers=(`sed -n -e "/^[^ #].*:/s/:.*//p" /etc/printcap`) + complete lpr 'c/-P/$printers/' + complete lpq 'c/-P/$printers/' + complete lprm 'c/-P/$printers/' +endif + +# Alternate prompts +set prompt = '#' +set prompt = '%B%m%b%# ' +set prompt = '%B%m%b:%c03:%# ' +set prompt = '%{\033]0;%n@%m:%/\007%}%B%m%b:%c03:%# ' +set prompt = "%n@%m %c04%m%# " +set prompt = "%n@%m:%c04 %# " +set prompt = "[%n@%m]%c04%# " +set ellipsis + +# Color ls +alias ll ls -lAhG +alias ls ls -G + +# Color on many system utilities +setenv CLICOLOR 1 + +# other autolist options +set autolist = TAB diff --git a/share/examples/drivers/README b/share/examples/drivers/README new file mode 100644 index 000000000000..8628029a62f8 --- /dev/null +++ b/share/examples/drivers/README @@ -0,0 +1,42 @@ + +Author: Julian Elischer + +The files in this directory are shell scripts. + +They will, when run, create an example skeleton driver +for you. You can use this driver as a starting point for +writing drivers for your own devices. They have all the hooks needed +for initialization, probing, attaching, as well as DEVFS +node creation. They also create sample ioctl commands and a sample +ioctl definition .h file in /sys/sys. In other words they are fully +functional in a 'skeleton' sort of a way. They support multiple devices +so that you may have several of your 'foobar' devices probed and attached +at once. + +I expect that these scripts will improve with time. + +At present these scripts also link the newly created driver into +the kernel sources in /sys. Possibly a better way would be +to make them interactive. (and ask what kernel tree to use as well as +a name for the driver.). + +There are presently two scripts. +One for making a real device driver for ISA devices, and +one for making a device driver for pseudo devices (e.g. /dev/null). +Hopefully they will be joined by similar scripts for creating +skeletons for PCI devices as well. + +Give them a single argument: the name of the driver. +They will use this given name in many places within the driver, +both in lower and upper case form. (conforming to normal usage). + +The skeleton driver should already link with the kernel +and in fact the shell script will compile a kernel with the new +drive linked in.. The new kernel should still be +runnable and the new driver should be +fully callable (once you get your device to probe). +You should simply edit the driver and continue to use +'make' (as done in the script) until your driver does what you want. + +The driver will end up in /sys/i386/isa for the device driver script, +and in /sys/dev for the pseudo driver script. diff --git a/share/examples/drivers/make_device_driver.sh b/share/examples/drivers/make_device_driver.sh new file mode 100755 index 000000000000..5b8f8efa6469 --- /dev/null +++ b/share/examples/drivers/make_device_driver.sh @@ -0,0 +1,1005 @@ +#!/bin/sh +# This writes a skeleton driver and puts it into the kernel tree for you. +# It also adds FOO and files.FOO configuration files so you can compile +# a kernel with your FOO driver linked in. +# To do so: +# cd /usr/src; make buildkernel KERNCONF=FOO +# +# More interestingly, it creates a modules/foo directory +# which it populates, to allow you to compile a FOO module +# which can be linked with your presently running kernel (if you feel brave). +# To do so: +# cd /sys/modules/foo; make depend; make; make install; kldload foo +# +# arg1 to this script is expected to be lowercase "foo" +# arg2 path to the kernel sources, "/sys" if omitted +# +# Trust me, RUN THIS SCRIPT :) +# +# TODO: +# o generate foo_isa.c, foo_pci.c, foo_pccard.c, foo_cardbus.c, and foovar.h +# o Put pccard stuff in here. +# +# +# +if [ "X${1}" = "X" ]; then + echo "Hey, how about some help here... give me a device name!" + exit 1 +fi +if [ "X${2}" = "X" ]; then + TOP=`cd /sys; pwd -P` + echo "Using ${TOP} as the path to the kernel sources!" +else + TOP=${2} +fi +UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` + +if [ -d ${TOP}/modules/${1} ]; then + echo "There appears to already be a module called ${1}" + echo -n "Should it be overwritten? [Y]" + read VAL + if [ "-z" "$VAL" ]; then + VAL=YES + fi + case ${VAL} in + [yY]*) + echo "Cleaning up from prior runs" + rm -rf ${TOP}/dev/${1} + rm -rf ${TOP}/modules/${1} + rm ${TOP}/conf/files.${UPPER} + rm ${TOP}/i386/conf/${UPPER} + rm ${TOP}/sys/${1}io.h + ;; + *) + exit 1 + ;; + esac +fi + +echo "The following files will be created:" +echo ${TOP}/modules/${1} +echo ${TOP}/conf/files.${UPPER} +echo ${TOP}/i386/conf/${UPPER} +echo ${TOP}/dev/${1} +echo ${TOP}/dev/${1}/${1}.c +echo ${TOP}/sys/${1}io.h +echo ${TOP}/modules/${1} +echo ${TOP}/modules/${1}/Makefile + + mkdir ${TOP}/modules/${1} + +####################################################################### +####################################################################### +# +# Create configuration information needed to create a kernel +# containing this driver. +# +# Not really needed if we are going to do this as a module. +####################################################################### +# First add the file to a local file list. +####################################################################### + +cat >${TOP}/conf/files.${UPPER} <<DONE +dev/${1}/${1}.c optional ${1} +DONE + +####################################################################### +# Then create a configuration file for a kernel that contains this driver. +####################################################################### +cat >${TOP}/i386/conf/${UPPER} <<DONE +# Configuration file for kernel type: ${UPPER} + +files "${TOP}/conf/files.${UPPER}" + +include GENERIC + +ident ${UPPER} + +DONE + +cat >>${TOP}/i386/conf/${UPPER} <<DONE +# trust me, you'll need this +options KDB +options DDB +device ${1} +DONE + +if [ ! -d ${TOP}/dev/${1} ]; then + mkdir -p ${TOP}/dev/${1} +fi + +cat >${TOP}/dev/${1}/${1}.c <<DONE +/* + * Copyright (c) [year] [your name] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * http://www.daemonnews.org/200008/isa.html is required reading. + * hopefully it will make it's way into the handbook. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> /* cdevsw stuff */ +#include <sys/kernel.h> /* SYSINIT stuff */ +#include <sys/uio.h> /* SYSINIT stuff */ +#include <sys/malloc.h> /* malloc region definitions */ +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/proc.h> +#include <sys/time.h> +#include <sys/${1}io.h> /* ${1} IOCTL definitions */ + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <isa/isavar.h> + +#include "isa_if.h" + +/* XXX These should be defined in terms of bus-space ops. */ +#define ${UPPER}_INB(port) inb(port_start) +#define ${UPPER}_OUTB(port, val) ( port_start, (val)) +#define SOME_PORT 123 +#define EXPECTED_VALUE 0x42 + +/* + * The softc is automatically allocated by the parent bus using the + * size specified in the driver_t declaration below. + */ +#define DEV2SOFTC(dev) ((struct ${1}_softc *) (dev)->si_drv1) +#define DEVICE2SOFTC(dev) ((struct ${1}_softc *) device_get_softc(dev)) + +/* + * Device specific misc defines. + */ +#define BUFFERSIZE 1024 +#define NUMPORTS 4 +#define MEMSIZE (4 * 1024) /* Imaginable h/w buffer size. */ + +/* + * One of these per allocated device. + */ +struct ${1}_softc { + bus_space_tag_t bt; + bus_space_handle_t bh; + int rid_ioport; + int rid_memory; + int rid_irq; + int rid_drq; + struct resource* res_ioport; /* Resource for port range. */ + struct resource* res_memory; /* Resource for mem range. */ + struct resource* res_irq; /* Resource for irq range. */ + struct resource* res_drq; /* Resource for dma channel. */ + device_t device; + struct cdev *dev; + void *intr_cookie; + void *vaddr; /* Virtual address of mem resource. */ + char buffer[BUFFERSIZE]; /* If we need to buffer something. */ +}; + +/* Function prototypes (these should all be static). */ +static int ${1}_deallocate_resources(device_t device); +static int ${1}_allocate_resources(device_t device); +static int ${1}_attach(device_t device, struct ${1}_softc *scp); +static int ${1}_detach(device_t device, struct ${1}_softc *scp); + +static d_open_t ${1}open; +static d_close_t ${1}close; +static d_read_t ${1}read; +static d_write_t ${1}write; +static d_ioctl_t ${1}ioctl; +static d_mmap_t ${1}mmap; +static d_poll_t ${1}poll; +static void ${1}intr(void *arg); + +static struct cdevsw ${1}_cdevsw = { + .d_version = D_VERSION, + .d_open = ${1}open, + .d_close = ${1}close, + .d_read = ${1}read, + .d_write = ${1}write, + .d_ioctl = ${1}ioctl, + .d_poll = ${1}poll, + .d_mmap = ${1}mmap, + .d_name = "${1}", +}; + +static devclass_t ${1}_devclass; + +/* + ****************************************** + * ISA Attachment structures and functions. + ****************************************** + */ +static void ${1}_isa_identify (driver_t *, device_t); +static int ${1}_isa_probe (device_t); +static int ${1}_isa_attach (device_t); +static int ${1}_isa_detach (device_t); + +static struct isa_pnp_id ${1}_ids[] = { + {0x12345678, "ABCco Widget"}, + {0xfedcba98, "shining moon Widget ripoff"}, + {0, NULL} +}; + +static device_method_t ${1}_methods[] = { + DEVMETHOD(device_identify, ${1}_isa_identify), + DEVMETHOD(device_probe, ${1}_isa_probe), + DEVMETHOD(device_attach, ${1}_isa_attach), + DEVMETHOD(device_detach, ${1}_isa_detach), + DEVMETHOD_END +}; + +static driver_t ${1}_isa_driver = { + "${1}", + ${1}_methods, + sizeof (struct ${1}_softc) +}; + +DRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0); + +/* + * Here list some port addresses we might expect our widget to appear at: + * This list should only be used for cards that have some non-destructive + * (to other cards) way of probing these address. Otherwise the driver + * should not go looking for instances of itself, but instead rely on + * the hints file. Strange failures for people with other cards might + * result. + */ +static struct localhints { + int ioport; + int irq; + int drq; + int mem; +} res[] = { + { 0x210, 11, 2, 0xcd000}, + { 0x310, 12, 3, 0xdd000}, + { 0x320, 9, 6, 0xd4000}, + {0,0,0,0} +}; + +#define MAXHINTS 10 /* Just an arbitrary safety limit. */ +/* + * Called once when the driver is somehow connected with the bus, + * (Either linked in and the bus is started, or loaded as a module). + * + * The aim of this routine in an ISA driver is to add child entries to + * the parent bus so that it looks as if the devices were detected by + * some pnp-like method, or at least mentioned in the hints. + * + * For NON-PNP "dumb" devices: + * Add entries into the bus's list of likely devices, so that + * our 'probe routine' will be called for them. + * This is similar to what the 'hints' code achieves, except this is + * loadable with the driver. + * In the 'dumb' case we end up with more children than needed but + * some (or all) of them will fail probe() and only waste a little memory. + * + * For NON-PNP "Smart" devices: + * If the device has a NON-PNP way of being detected and setting/sensing + * the card, then do that here and add a child for each set of + * hardware found. + * + * For PNP devices: + * If the device is always PNP capable then this function can be removed. + * The ISA PNP system will have automatically added it to the system and + * so your identify routine needn't do anything. + * + * If the device is mentioned in the 'hints' file then this + * function can be removed. All devices mentioned in the hints + * file get added as children for probing, whether or not the + * driver is linked in. So even as a module it MAY still be there. + * See isa/isahint.c for hints being added in. + */ +static void +${1}_isa_identify (driver_t *driver, device_t parent) +{ + u_int32_t irq=0; + u_int32_t ioport; + device_t child; + int i; + + /* + * If we've already got ${UPPER} attached somehow, don't try again. + * Maybe it was in the hints file. or it was loaded before. + */ + if (device_find_child(parent, "${1}", 0)) { + printf("${UPPER}: already attached\n"); + return; + } +/* XXX Look at dev/acpica/acpi_isa.c for use of ISA_ADD_CONFIG() macro. */ +/* XXX What is ISA_SET_CONFIG_CALLBACK(parent, child, pnpbios_set_config, 0)? */ + for (i = 0; i < MAXHINTS; i++) { + + ioport = res[i].ioport; + irq = res[i].irq; + if ((ioport == 0) && (irq == 0)) + return; /* We've added all our local hints. */ + + child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "${1}", -1); + bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, NUMPORTS); + bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); + bus_set_resource(child, SYS_RES_DRQ, 0, res[i].drq, 1); + bus_set_resource(child, SYS_RES_MEMORY, 0, res[i].mem, MEMSIZE); + +#if 0 + /* + * If we wanted to pretend PNP found it + * we could do this, and put matching entries + * in the PNP table, but I think it's probably too hacky. + * As you see, some people have done it though. + * Basically EISA (remember that?) would do this I think. + */ + isa_set_vendorid(child, PNP_EISAID("ESS1888")); + isa_set_logicalid(child, PNP_EISAID("ESS1888")); +#endif + } +#if 0 + /* + * Do some smart probing (e.g. like the lnc driver) + * and add a child for each one found. + */ +#endif + + return; +} +/* + * The ISA code calls this for each device it knows about, + * whether via the PNP code or via the hints etc. + * If the device nas no PNP capabilities, remove all the + * PNP entries, but keep the call to ISA_PNP_PROBE() + * As it will guard against accidentally recognising + * foreign hardware. This is because we will be called to check against + * ALL PNP hardware. + */ +static int +${1}_isa_probe (device_t device) +{ + int error; + device_t parent = device_get_parent(device); + struct ${1}_softc *scp = DEVICE2SOFTC(device); + u_long port_start, port_count; + + bzero(scp, sizeof(*scp)); + scp->device = device; + + /* + * Check this device for a PNP match in our table. + * There are several possible outcomes. + * error == 0 We match a PNP. + * error == ENXIO, It is a PNP device but not in our table. + * error == ENOENT, It is not a PNP device.. try heuristic probes. + * -- logic from if_ed_isa.c, added info from isa/isa_if.m: + * + * If we had a list of devices that we could handle really well, + * and a list which we could handle only basic functions, then + * we would call this twice, once for each list, + * and return a value of '-2' or something if we could + * only handle basic functions. This would allow a specific + * Widgetplus driver to make a better offer if it knows how to + * do all the extended functions. (See non-pnp part for more info). + */ + error = ISA_PNP_PROBE(parent, device, ${1}_ids); + switch (error) { + case 0: + /* + * We found a PNP device. + * Do nothing, as it's all done in attach(). + */ + break; + case ENOENT: + /* + * Well it didn't show up in the PNP tables + * so look directly at known ports (if we have any) + * in case we are looking for an old pre-PNP card. + * + * Hopefully the 'identify' routine will have picked these + * up for us first if they use some proprietary detection + * method. + * + * The ports, irqs etc should come from a 'hints' section + * which is read in by code in isa/isahint.c + * and kern/subr_bus.c to create resource entries, + * or have been added by the 'identify routine above. + * Note that HINTS based resource requests have NO + * SIZE for the memory or ports requests (just a base) + * so we may need to 'correct' this before we + * do any probing. + */ + /* + * Find out the values of any resources we + * need for our dumb probe. Also check we have enough ports + * in the request. (could be hints based). + * Should probably do the same for memory regions too. + */ + error = bus_get_resource(device, SYS_RES_IOPORT, 0, + &port_start, &port_count); + if (port_count != NUMPORTS) { + bus_set_resource(device, SYS_RES_IOPORT, 0, + port_start, NUMPORTS); + } + + /* + * Make a temporary resource reservation. + * If we can't get the resources we need then + * we need to abort. Possibly this indicates + * the resources were used by another device + * in which case the probe would have failed anyhow. + */ + if ((error = (${1}_allocate_resources(device)))) { + error = ENXIO; + goto errexit; + } + + /* Dummy heuristic type probe. */ + if (inb(port_start) != EXPECTED_VALUE) { + /* + * It isn't what we hoped, so quit looking for it. + */ + error = ENXIO; + } else { + u_long membase = bus_get_resource_start(device, + SYS_RES_MEMORY, 0 /*rid*/); + u_long memsize; + /* + * If we discover in some way that the device has + * XXX bytes of memory window, we can override + * or set the memory size in the child resource list. + */ + memsize = inb(port_start + 1) * 1024; /* for example */ + error = bus_set_resource(device, SYS_RES_MEMORY, + /*rid*/0, membase, memsize); + /* + * We found one, return non-positive numbers.. + * Return -N if we can't handle it, but not well. + * Return -2 if we would LIKE the device. + * Return -1 if we want it a lot. + * Return 0 if we MUST get the device. + * This allows drivers to 'bid' for a device. + */ + device_set_desc(device, "ACME Widget model 1234"); + error = -1; /* We want it but someone else + may be even better. */ + } + /* + * Unreserve the resources for now because + * another driver may bid for device too. + * If we lose the bid, but still hold the resources, we will + * effectively have disabled the other driver from getting them + * which will result in neither driver getting the device. + * We will ask for them again in attach if we win. + */ + ${1}_deallocate_resources(device); + break; + case ENXIO: + /* It was PNP but not ours, leave immediately. */ + default: + error = ENXIO; + } +errexit: + return (error); +} + +/* + * Called if the probe succeeded and our bid won the device. + * We can be destructive here as we know we have the device. + * This is the first place we can be sure we have a softc structure. + * You would do ISA specific attach things here, but generically there aren't + * any (yay new-bus!). + */ +static int +${1}_isa_attach (device_t device) +{ + int error; + struct ${1}_softc *scp = DEVICE2SOFTC(device); + + error = ${1}_attach(device, scp); + if (error) + ${1}_isa_detach(device); + return (error); +} + +/* + * Detach the driver (e.g. module unload), + * call the bus independent version + * and undo anything we did in the ISA attach routine. + */ +static int +${1}_isa_detach (device_t device) +{ + int error; + struct ${1}_softc *scp = DEVICE2SOFTC(device); + + error = ${1}_detach(device, scp); + return (error); +} + +/* + *************************************** + * PCI Attachment structures and code + *************************************** + */ + +static int ${1}_pci_probe(device_t); +static int ${1}_pci_attach(device_t); +static int ${1}_pci_detach(device_t); + +static device_method_t ${1}_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ${1}_pci_probe), + DEVMETHOD(device_attach, ${1}_pci_attach), + DEVMETHOD(device_detach, ${1}_pci_detach), + { 0, 0 } +}; + +static driver_t ${1}_pci_driver = { + "${1}", + ${1}_pci_methods, + sizeof(struct ${1}_softc), +}; + +DRIVER_MODULE(${1}, pci, ${1}_pci_driver, ${1}_devclass, 0, 0); +/* + * Cardbus is a pci bus plus extra, so use the pci driver unless special + * things need to be done only in the cardbus case. + */ +DRIVER_MODULE(${1}, cardbus, ${1}_pci_driver, ${1}_devclass, 0, 0); + +static struct _pcsid +{ + u_int32_t type; + const char *desc; +} pci_ids[] = { + { 0x1234abcd, "ACME PCI Widgetplus" }, + { 0x1243fedc, "Happy moon brand RIPOFFplus" }, + { 0x00000000, NULL } +}; + +/* + * See if this card is specifically mentioned in our list of known devices. + * Theoretically we might also put in a weak bid for some devices that + * report themselves to be some generic type of device if we can handle + * that generic type. (other PCI_XXX calls give that info). + * This would allow a specific driver to over-ride us. + * + * See the comments in the ISA section regarding returning non-positive + * values from probe routines. + */ +static int +${1}_pci_probe (device_t device) +{ + u_int32_t type = pci_get_devid(device); + struct _pcsid *ep =pci_ids; + + while (ep->type && ep->type != type) + ++ep; + if (ep->desc) { + device_set_desc(device, ep->desc); + return 0; /* If there might be a better driver, return -2 */ + } else + return ENXIO; +} + +static int +${1}_pci_attach(device_t device) +{ + int error; + struct ${1}_softc *scp = DEVICE2SOFTC(device); + + error = ${1}_attach(device, scp); + if (error) + ${1}_pci_detach(device); + return (error); +} + +static int +${1}_pci_detach (device_t device) +{ + int error; + struct ${1}_softc *scp = DEVICE2SOFTC(device); + + error = ${1}_detach(device, scp); + return (error); +} + +/* + **************************************** + * Common Attachment sub-functions + **************************************** + */ +static int +${1}_attach(device_t device, struct ${1}_softc * scp) +{ + device_t parent = device_get_parent(device); + int unit = device_get_unit(device); + + scp->dev = make_dev(&${1}_cdevsw, 0, + UID_ROOT, GID_OPERATOR, 0600, "${1}%d", unit); + scp->dev->si_drv1 = scp; + + if (${1}_allocate_resources(device)) + goto errexit; + + scp->bt = rman_get_bustag(scp->res_ioport); + scp->bh = rman_get_bushandle(scp->res_ioport); + + /* Register the interrupt handler. */ + /* + * The type should be one of: + * INTR_TYPE_TTY + * INTR_TYPE_BIO + * INTR_TYPE_CAM + * INTR_TYPE_NET + * INTR_TYPE_MISC + * This will probably change with SMPng. INTR_TYPE_FAST may be + * OR'd into this type to mark the interrupt fast. However, fast + * interrupts cannot be shared at all so special precautions are + * necessary when coding fast interrupt routines. + */ + if (scp->res_irq) { + /* Default to the tty mask for registration. */ /* XXX */ + if (BUS_SETUP_INTR(parent, device, scp->res_irq, INTR_TYPE_TTY, + ${1}intr, scp, &scp->intr_cookie) == 0) { + /* Do something if successful. */ + } else + goto errexit; + } + + /* + * If we want to access the memory we will need + * to know where it was mapped. + * + * Use of this function is discouraged, however. You should + * be accessing the device with the bus_space API if at all + * possible. + */ + scp->vaddr = rman_get_virtual(scp->res_memory); + return 0; + +errexit: + /* + * Undo anything we may have done. + */ + ${1}_detach(device, scp); + return (ENXIO); +} + +static int +${1}_detach(device_t device, struct ${1}_softc *scp) +{ + device_t parent = device_get_parent(device); + + /* + * At this point stick a strong piece of wood into the device + * to make sure it is stopped safely. The alternative is to + * simply REFUSE to detach if it's busy. What you do depends on + * your specific situation. + * + * Sometimes the parent bus will detach you anyway, even if you + * are busy. You must cope with that possibility. Your hardware + * might even already be gone in the case of cardbus or pccard + * devices. + */ + /* ZAP some register */ + + /* + * Take our interrupt handler out of the list of handlers + * that can handle this irq. + */ + if (scp->intr_cookie != NULL) { + if (BUS_TEARDOWN_INTR(parent, device, + scp->res_irq, scp->intr_cookie) != 0) + printf("intr teardown failed.. continuing\n"); + scp->intr_cookie = NULL; + } + + /* + * Deallocate any system resources we may have + * allocated on behalf of this driver. + */ + scp->vaddr = NULL; + return ${1}_deallocate_resources(device); +} + +static int +${1}_allocate_resources(device_t device) +{ + int error; + struct ${1}_softc *scp = DEVICE2SOFTC(device); + int size = 16; /* SIZE of port range used. */ + + scp->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT, + &scp->rid_ioport, 0ul, ~0ul, size, RF_ACTIVE); + if (scp->res_ioport == NULL) + goto errexit; + + scp->res_irq = bus_alloc_resource(device, SYS_RES_IRQ, + &scp->rid_irq, 0ul, ~0ul, 1, RF_SHAREABLE|RF_ACTIVE); + if (scp->res_irq == NULL) + goto errexit; + + scp->res_drq = bus_alloc_resource(device, SYS_RES_DRQ, + &scp->rid_drq, 0ul, ~0ul, 1, RF_ACTIVE); + if (scp->res_drq == NULL) + goto errexit; + + scp->res_memory = bus_alloc_resource(device, SYS_RES_MEMORY, + &scp->rid_memory, 0ul, ~0ul, MSIZE, RF_ACTIVE); + if (scp->res_memory == NULL) + goto errexit; + return (0); + +errexit: + error = ENXIO; + /* Cleanup anything we may have assigned. */ + ${1}_deallocate_resources(device); + return (ENXIO); /* For want of a better idea. */ +} + +static int +${1}_deallocate_resources(device_t device) +{ + struct ${1}_softc *scp = DEVICE2SOFTC(device); + + if (scp->res_irq != 0) { + bus_deactivate_resource(device, SYS_RES_IRQ, + scp->rid_irq, scp->res_irq); + bus_release_resource(device, SYS_RES_IRQ, + scp->rid_irq, scp->res_irq); + scp->res_irq = 0; + } + if (scp->res_ioport != 0) { + bus_deactivate_resource(device, SYS_RES_IOPORT, + scp->rid_ioport, scp->res_ioport); + bus_release_resource(device, SYS_RES_IOPORT, + scp->rid_ioport, scp->res_ioport); + scp->res_ioport = 0; + } + if (scp->res_memory != 0) { + bus_deactivate_resource(device, SYS_RES_MEMORY, + scp->rid_memory, scp->res_memory); + bus_release_resource(device, SYS_RES_MEMORY, + scp->rid_memory, scp->res_memory); + scp->res_memory = 0; + } + if (scp->res_drq != 0) { + bus_deactivate_resource(device, SYS_RES_DRQ, + scp->rid_drq, scp->res_drq); + bus_release_resource(device, SYS_RES_DRQ, + scp->rid_drq, scp->res_drq); + scp->res_drq = 0; + } + if (scp->dev) + destroy_dev(scp->dev); + return (0); +} + +static void +${1}intr(void *arg) +{ + struct ${1}_softc *scp = (struct ${1}_softc *) arg; + + /* + * Well we got an interrupt, now what? + * + * Make sure that the interrupt routine will always terminate, + * even in the face of "bogus" data from the card. + */ + (void)scp; /* Delete this line after using scp. */ + return; +} + +static int +${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + + (void)scp; /* Delete this line after using scp. */ + switch (cmd) { + case DHIOCRESET: + /* Whatever resets it. */ +#if 0 + ${UPPER}_OUTB(SOME_PORT, 0xff); +#endif + break; + default: + return ENXIO; + } + return (0); +} +/* + * You also need read, write, open, close routines. + * This should get you started. + */ +static int +${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + + /* + * Do processing. + */ + (void)scp; /* Delete this line after using scp. */ + return (0); +} + +static int +${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + + /* + * Do processing. + */ + (void)scp; /* Delete this line after using scp. */ + return (0); +} + +static int +${1}read(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + int toread; + + /* + * Do processing. + * Read from buffer. + */ + (void)scp; /* Delete this line after using scp. */ + toread = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, toread, uio)); +} + +static int +${1}write(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + int towrite; + + /* + * Do processing. + * Write to buffer. + */ + (void)scp; /* Delete this line after using scp. */ + towrite = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, towrite, uio)); +} + +static int +${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + + /* + * Given a byte offset into your device, return the PHYSICAL + * page number that it would map to. + */ + (void)scp; /* Delete this line after using scp. */ +#if 0 /* If we had a frame buffer or whatever... do this. */ + if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) + return (-1); + return i386_btop((FRAMEBASE + offset)); +#else + return (-1); +#endif +} + +static int +${1}poll(struct cdev *dev, int which, struct thread *td) +{ + struct ${1}_softc *scp = DEV2SOFTC(dev); + + /* + * Do processing. + */ + (void)scp; /* Delete this line after using scp. */ + return (0); /* This is the wrong value I'm sure. */ +} + +DONE + +cat >${TOP}/sys/${1}io.h <<DONE +/* + * Definitions needed to access the ${1} device (ioctls etc) + * see mtio.h, ioctl.h as examples. + */ +#ifndef SYS_DHIO_H +#define SYS_DHIO_H + +#ifndef KERNEL +#include <sys/types.h> +#endif +#include <sys/ioccom.h> + +/* + * Define an ioctl here. + */ +#define DHIOCRESET _IO('D', 0) /* Reset the ${1} device. */ +#endif +DONE + +if [ ! -d ${TOP}/modules/${1} ]; then + mkdir -p ${TOP}/modules/${1} +fi + +cat >${TOP}/modules/${1}/Makefile <<DONE +# ${UPPER} Loadable Kernel Module + +.PATH: \${.CURDIR}/../../dev/${1} +KMOD = ${1} +SRCS = ${1}.c +SRCS += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h + +# You may need to do this is your device is an if_xxx driver. +opt_inet.h: + echo "#define INET 1" > opt_inet.h + +.include <bsd.kmod.mk> +DONE + +echo -n "Do you want to build the '${1}' module? [Y]" +read VAL +if [ "-z" "$VAL" ]; then + VAL=YES +fi +case ${VAL} in +[yY]*) + (cd ${TOP}/modules/${1}; make depend; make ) + ;; +*) +# exit + ;; +esac + +echo "" +echo -n "Do you want to build the '${UPPER}' kernel? [Y]" +read VAL +if [ "-z" "$VAL" ]; then + VAL=YES +fi +case ${VAL} in +[yY]*) + ( + cd ${TOP}/i386/conf; \ + config ${UPPER}; \ + cd ${TOP}/i386/compile/${UPPER}; \ + make depend; \ + make; \ + ) + ;; +*) +# exit + ;; +esac + +#--------------end of script--------------- +# +# Edit to your taste... +# +# diff --git a/share/examples/drivers/make_pseudo_driver.sh b/share/examples/drivers/make_pseudo_driver.sh new file mode 100644 index 000000000000..5d6d09aa9648 --- /dev/null +++ b/share/examples/drivers/make_pseudo_driver.sh @@ -0,0 +1,435 @@ +#!/bin/sh +# This writes a skeleton driver and puts it into the kernel tree for you +# +# arg1 is lowercase "foo" +# arg2 path to the kernel sources, "/sys" if omitted +# +# Trust me, RUN THIS SCRIPT :) +# +# +#-------cut here------------------ + +if [ "${1}X" = "X" ] +then + echo "Hey , how about some help here.. give me a device name!" + exit 1 +fi +if [ "X${2}" = "X" ]; then + TOP=`cd /sys; pwd -P` + echo "Using ${TOP} as the path to the kernel sources!" +else + TOP=${2} +fi + +for i in "" "conf" "i386" "i386/conf" "dev" "sys" "modules" +do + if [ -d ${TOP}/${i} ] + then + continue + fi + echo "${TOP}/${i}: no such directory." + echo "Please, correct the error and try again." + exit 1 +done + +UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` + +if [ -d ${TOP}/modules/${1} ]; then + echo "There appears to already be a module called ${1}" + echo -n "Should it be overwritten? [Y]" + read VAL + if [ "-z" "$VAL" ]; then + VAL=YES + fi + case ${VAL} in + [yY]*) + echo "Cleaning up from prior runs" + rm -rf ${TOP}/dev/${1} + rm -rf ${TOP}/modules/${1} + rm ${TOP}/conf/files.${UPPER} + rm ${TOP}/i386/conf/${UPPER} + rm ${TOP}/sys/${1}io.h + ;; + *) + exit 1 + ;; + esac +fi + +echo "The following files will be created:" +echo ${TOP}/modules/${1} +echo ${TOP}/conf/files.${UPPER} +echo ${TOP}/i386/conf/${UPPER} +echo ${TOP}/dev/${1} +echo ${TOP}/dev/${1}/${1}.c +echo ${TOP}/sys/${1}io.h +echo ${TOP}/modules/${1} +echo ${TOP}/modules/${1}/Makefile + +mkdir ${TOP}/modules/${1} + +cat >${TOP}/conf/files.${UPPER} <<DONE +dev/${1}/${1}.c optional ${1} +DONE + +cat >${TOP}/i386/conf/${UPPER} <<DONE +# Configuration file for kernel type: ${UPPER} + +files "${TOP}/conf/files.${UPPER}" + +include GENERIC + +ident ${UPPER} + +# trust me, you'll need this +options KDB +options DDB +device ${1} +DONE + +if [ ! -d ${TOP}/dev/${1} ]; then + mkdir -p ${TOP}/dev/${1} +fi + +cat >${TOP}/dev/${1}/${1}.c <<DONE +/* + * Copyright (c) [year] [your name] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * ${1} driver + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> /* SYSINIT stuff */ +#include <sys/uio.h> /* SYSINIT stuff */ +#include <sys/conf.h> /* cdevsw stuff */ +#include <sys/malloc.h> /* malloc region definitions */ +#include <sys/proc.h> +#include <sys/${1}io.h> /* ${1} IOCTL definitions */ + +#include <machine/clock.h> /* DELAY() */ + +#define N${UPPER} 3 /* defines number of instances */ + +/* XXX These should be defined in terms of bus-space ops. */ +#define ${UPPER}_INB(port) inb(port) +#define ${UPPER}_OUTB(port, val) (port, (val)) + +/* Function prototypes (these should all be static) */ +static d_open_t ${1}open; +static d_close_t ${1}close; +static d_read_t ${1}read; +static d_write_t ${1}write; +static d_ioctl_t ${1}ioctl; +static d_mmap_t ${1}mmap; +static d_poll_t ${1}poll; + +#define CDEV_MAJOR 20 +static struct cdevsw ${1}_cdevsw = { + .d_version = D_VERSION, + .d_open = ${1}open, + .d_close = ${1}close, + .d_read = ${1}read, + .d_write = ${1}write, + .d_ioctl = ${1}ioctl, + .d_poll = ${1}poll, + .d_mmap = ${1}mmap, + .d_name = "${1}", +}; + +/* + * device specific Misc defines + */ +#define BUFFERSIZE 1024 +#define UNIT(dev) dev2unit(dev) /* assume one minor number per unit */ + +/* + * One of these per allocated device + */ +struct ${1}_softc { + u_long iobase; + char buffer[BUFFERSIZE]; + struct cdev *dev; +}; + +typedef struct ${1}_softc *sc_p; + +static sc_p sca[N${UPPER}]; + +/* + * Macro to check that the unit number is valid + * Often this isn't needed as once the open() is performed, + * the unit number is pretty much safe.. The exception would be if we + * implemented devices that could "go away". in which case all these routines + * would be wise to check the number, DIAGNOSTIC or not. + */ +#define CHECKUNIT(RETVAL) \ +do { /* the do-while is a safe way to do this grouping */ \ + if (unit > N${UPPER}) { \ + printf("%s: bad unit %d\n", __func__, unit); \ + return (RETVAL); \ + } \ + if (scp == NULL) { \ + printf("%s: unit %d not attached\n", __func__, unit); \ + return (RETVAL); \ + } \ +} while (0) + +#ifdef DIAGNOSTIC +#define CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL) +#else /* DIAGNOSTIC */ +#define CHECKUNIT_DIAG(RETVAL) +#endif /* DIAGNOSTIC */ + +static int +${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + switch (cmd) { + case DHIOCRESET: + /* whatever resets it */ + (void)scp; /* Delete this line after using scp. */ +#if 0 + ${UPPER}_OUTB(scp->iobase, 0xff); +#endif + break; + default: + return ENXIO; + } + return (0); +} + +/* + * You also need read, write, open, close routines. + * This should get you started + */ +static int +${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + + CHECKUNIT(ENXIO); + + (void)scp; /* Delete this line after using scp. */ + /* + * Do processing + */ + return (0); +} + +static int +${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + (void)scp; /* Delete this line after using scp. */ + /* + * Do processing + */ + return (0); +} + +static int +${1}read(struct cdev *dev, struct uio *uio, int ioflag) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + int toread; + + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + * read from buffer + */ + toread = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, toread, uio)); +} + +static int +${1}write(struct cdev *dev, struct uio *uio, int ioflag) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + int towrite; + + CHECKUNIT_DIAG(ENXIO); + + /* + * Do processing + * write to buffer + */ + towrite = (min(uio->uio_resid, sizeof(scp->buffer))); + return(uiomove(scp->buffer, towrite, uio)); +} + +static int +${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(-1); + + (void)scp; /* Delete this line after using scp. */ + /* + * Do processing + */ +#if 0 /* if we had a frame buffer or whatever.. do this */ + if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) { + return (-1); + } + return i386_btop((FRAMEBASE + offset)); +#else + return (-1); +#endif +} + +static int +${1}poll(struct cdev *dev, int which, struct thread *td) +{ + int unit = UNIT(dev); + sc_p scp = sca[unit]; + + CHECKUNIT_DIAG(ENXIO); + + (void)scp; /* Delete this line after using scp. */ + /* + * Do processing + */ + return (0); /* this is the wrong value I'm sure */ +} + +/* + * Now for some driver initialisation. + * Occurs ONCE during boot (very early). + */ +static void +${1}_drvinit(void *unused) +{ + int unit; + sc_p scp; + + for (unit = 0; unit < N${UPPER}; unit++) { + /* + * Allocate storage for this instance . + */ + scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO); + if( scp == NULL) { + printf("${1}%d failed to allocate strorage\n", unit); + return; + } + sca[unit] = scp; + scp->dev = make_dev(&${1}_cdevsw, unit, + UID_ROOT, GID_KMEM, 0640, "${1}%d", unit); + } +} + +SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR, + ${1}_drvinit, NULL); +DONE + +cat >${TOP}/sys/${1}io.h <<DONE +/* + * Definitions needed to access the ${1} device (ioctls etc) + * see mtio.h , ioctl.h as examples + */ +#ifndef SYS_DHIO_H +#define SYS_DHIO_H + +#ifndef KERNEL +#include <sys/types.h> +#endif +#include <sys/ioccom.h> + +/* + * define an ioctl here + */ +#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */ +#endif +DONE + +if [ ! -d ${TOP}/modules/${1} ]; then + mkdir -p ${TOP}/modules/${1} +fi + +cat >${TOP}/modules/${1}/Makefile <<DONE +# ${UPPER} Loadable Kernel Module + +.PATH: \${.CURDIR}/../../dev/${1} +KMOD = ${1} +SRCS = ${1}.c + +.include <bsd.kmod.mk> +DONE + +echo -n "Do you want to build the '${1}' module? [Y]" +read VAL +if [ "-z" "$VAL" ]; then + VAL=YES +fi +case ${VAL} in +[yY]*) + (cd ${TOP}/modules/${1}; make depend; make ) + ;; +*) +# exit + ;; +esac + +echo "" +echo -n "Do you want to build the '${UPPER}' kernel? [Y]" +read VAL +if [ "-z" "$VAL" ]; then + VAL=YES +fi +case ${VAL} in +[yY]*) + ( + cd ${TOP}/i386/conf; \ + config ${UPPER}; \ + cd ${TOP}/i386/compile/${UPPER}; \ + make depend; \ + make; \ + ) + ;; +*) +# exit + ;; +esac + +#--------------end of script--------------- +# +#edit to your taste.. +# +# diff --git a/share/examples/etc/README.examples b/share/examples/etc/README.examples new file mode 100644 index 000000000000..b0dc2b83ad66 --- /dev/null +++ b/share/examples/etc/README.examples @@ -0,0 +1,69 @@ + +The /usr/share/examples/etc directory contains the original +distribution versions of the files which are shipped in /etc. This is +intended to make it easy to recover when the /etc versions are +accidentally deleted or broken beyond repair. + +This directory contains the following files: + +amd.map - filesystem automounter lookup resolution map (see amd(8)) +apmd.conf - configuration file for apmd(8) +bsd-style-copyright - copyright style for bsd system +crontab - system scheduled command table (see crontab(5)) +csh.cshrc - sample .cshrc (see csh(1)) +csh.login - sample .login +csh.logout - sample .logout +defaults/ - directory containing default configuration file +devd.conf - configuration file for devd(8) +devfs.conf - configuration file for devfs(8) +dhclient.conf - configuration file for dhclient(8) +disktab - disk description file (see disktab(5)) +fbtab - configuration file for login(1) +ftpusers - user restriction file for ftpd(8) +gettytab - defines port configuration for getty(8) +group - group permissions file (see group(5)) +hosts - see hosts(5) +hosts.allow - defines allow trusted hosts +hosts.equiv - defines system-wide trusted hosts (see ruserok(3)) +hosts.lpd - defines trusted hosts for lpd(8) +inetd.conf - configuration file for inetd(8) +locate.rc - configuration file for locate(1) +login.access - configuration file for login(8) (see login.access(5)) +login.conf - login class capabilities database (see login.conf(5)) +mac.conf - TrustedBSD MAC userland policy configuration file +mail.rc - systemwide initialization files for mail(1) +make.conf - example configuration variables for system builds +motd - sample Message of the Day +netconfig - network configuration data base +netstart - network startup script run from /etc/rc +network.subr - routines for network configuration scripts +networks - see networks(5) +newsyslog.conf - configuration for system log file rotator newsyslog(8) +nsmb.conf - smbfs lookups configuration file +pf.conf - pf(4) example configuration file +pf.os - SYN fingerprint database +phones - phone number database for tip(1) +printcap - configuration file for lpr(1) +profile - system-wide .profile for sh(1) +protocols - see protocols(5) +rc - system startup script (see init(8)) +rc.bsdextended - startup policy for the mac_bsdextended(4) security module. +rc.firewall - ipfw(8) setup script with basic rulesets +rc.initdiskless - configuration file to boot a diskless machine +rc.resume - sample run command file for APM Resume Event +rc.shutdown - system shutdown script (see init(8)) +rc.subr - script with functions used by various rc scripts +rc.suspend - sample run command file for APM Resume Event +remote - configuration file for tip(1) +rpc - see rpc(5) +security - script run from crontab to do nightly security checks +services - see services(5) +shells - list of configurable shells (see shells(5)) +snmpd.config - example configuration file for bsnmpd(1) +sysctl.conf - configuration file for sysctl(8) +syslog.conf - configuration file for syslogd(8) +ttys - defines port configuration for init(8) +defaults/bluetooth.device.conf - +defaults/devfs.rules - default configuration rules for devfs(8) +defaults/periodic.conf - default configuration file for periodic(8) +defaults/rc.conf - default system configuration info (see rc.conf(5)) diff --git a/share/examples/etc/bsd-style-copyright b/share/examples/etc/bsd-style-copyright new file mode 100644 index 000000000000..5822943b54eb --- /dev/null +++ b/share/examples/etc/bsd-style-copyright @@ -0,0 +1,28 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) [year] [your name] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * [id for your version control system, if any] + */ diff --git a/share/examples/etc/make.conf b/share/examples/etc/make.conf new file mode 100644 index 000000000000..0cf156371aec --- /dev/null +++ b/share/examples/etc/make.conf @@ -0,0 +1,280 @@ +# +# NOTE: Please would any committer updating this file also update the +# make.conf(5) manual page, if necessary, which is located in +# src/share/man/man5/make.conf.5. +# +# /etc/make.conf, if present, will be read by make (see +# /usr/share/mk/sys.mk). It allows you to override macro definitions +# to make without changing your source tree, or anything the source +# tree installs. +# +# This file must be in valid Makefile syntax. +# +# There are additional things you can put into /etc/make.conf. +# You have to find those in the Makefiles and documentation of +# the source tree. +# +# Note, that you should not set MAKEOBJDIRPREFIX or MAKEOBJDIR +# from make.conf (or as command line variables to make). +# Both variables are environment variables for make and must be used as: +# +# env MAKEOBJDIRPREFIX=/big/directory make +# +# +# The CPUTYPE variable controls which processor should be targeted for +# generated code. This controls processor-specific optimizations in +# certain code (currently only OpenSSL) as well as modifying the value +# of CFLAGS to contain the appropriate optimization directive to cc. +# The automatic setting of CFLAGS may be overridden using the +# NO_CPU_CFLAGS variable below. +# Currently the following CPU types are recognized: +# Intel x86 architecture: +# (AMD CPUs) znver4, znver3, znver2, znver1, bdver4, bdver3, bdver2, +# bdver1, btver2, btver1, amdfam10, opteron-sse3, +# athlon64-sse3, k8-sse3, opteron, athlon64, athlon-fx, +# k8, athlon-mp, athlon-xp, athlon-4, athlon-tbird, +# athlon, k7, geode, k6-3, k6-2, k6 +# (Intel CPUs) alderlake, sapphirerapids, tigerlake, cooperlake, +# cascadelake, tremont, goldmont-plus, icelake-server, +# icelake-client, cannonlake, knm, skylake-avx512, knl, +# goldmont, skylake, broadwell, haswell, ivybridge, +# sandybridge, westmere, nehalem, silvermont, bonnell, +# core2, core, nocona, pentium4m, pentium4, prescott, +# pentium3m, pentium3, pentium-m, pentium2, pentiumpro, +# pentium-mmx, pentium, i486 +# (VIA CPUs) c7, c3-2, c3 +# ARM architecture: armv5, armv5te, armv6, armv6t2, arm1176jzf-s, armv7, +# armv7-a, armv7ve, generic-armv7-a, cortex-a5, +# cortex-a7, cortex-a8, cortex-a9, cortex-a12, +# cortex-a15, cortex-a17 +# ARM64 architecture: cortex-a53, cortex-a57, cortex-a72, +# exynos-m1 +# +# (?= allows to buildworld for a different CPUTYPE.) +# +#CPUTYPE?=pentium3 +#NO_CPU_CFLAGS= # Don't add -march=<cpu> to CFLAGS automatically +# +# CFLAGS controls the compiler settings used when compiling C code. +# Note that optimization settings other than -O and -O2 are not recommended +# or supported for compiling the world or the kernel - please revert any +# nonstandard optimization settings +# before submitting bug reports without patches to the developers. +# +# CFLAGS.arch provides a mechanism for applying CFLAGS only when building +# the given architecture. This is useful primarily on a system used for +# cross-building, when you have a set of flags to apply to the TARGET_ARCH +# being cross-built but don't want those settings applied to building the +# cross-tools or other components that run on the build host machine. +# +# CXXFLAGS controls the compiler settings used when compiling C++ code. +# Note that CXXFLAGS is initially set to the value of CFLAGS. If you wish +# to add to CXXFLAGS value, "+=" must be used rather than "=". Using "=" +# alone will remove the often needed contents of CFLAGS from CXXFLAGS. +# +# Additional compiler flags can be specified that extend or override +# default ones. However, neither the base system nor ports are guaranteed +# to build and function without problems with non-default settings. +# +# CFLAGS+= -msse3 +# CXXFLAGS+= -msse3 +# CFLAGS.armv6+= -mfloat-abi=softfp +# +# MAKE_SHELL controls the shell used internally by make(1) to process the +# command scripts in makefiles. Three shells are supported, sh, ksh, and +# csh. Using sh is most common, and advised. Using ksh *may* work, but is +# not guaranteed to. Using csh is absurd. The default is to use sh. +# +#MAKE_SHELL?=sh +# +# BDECFLAGS are a set of gcc warning settings that Bruce Evans has suggested +# for use in developing FreeBSD and testing changes. They can be used by +# putting "CFLAGS+=${BDECFLAGS}" in /etc/make.conf. -Wconversion is not +# included here due to compiler bugs, e.g., mkdir()'s mode_t argument. +# +#BDECFLAGS= -W -Wall -ansi -pedantic -Wbad-function-cast -Wcast-align \ +# -Wcast-qual -Wchar-subscripts -Winline \ +# -Wmissing-prototypes -Wnested-externs -Wpointer-arith \ +# -Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings +# +# To compile just the kernel with special optimizations, you should use +# this instead of CFLAGS (which is not applicable to kernel builds anyway). +# There is very little to gain by using higher optimization levels, and doing +# so can cause problems. +# +#COPTFLAGS= -O -pipe +# +# Compare before install. +#INSTALL+= -C +# +# Mtree will follow symlinks. +#MTREE_FOLLOWS_SYMLINKS= -L +# +# To enable installing newgrp(1) with the setuid bit turned on. +# Without the setuid bit, newgrp cannot change users' groups. +#ENABLE_SUID_NEWGRP= +# +# To avoid building various parts of the base system: +#NO_MODULES= # do not build modules with the kernel +#NO_SHARE= # do not go into the share subdir +#NO_SHARED= # build /bin and /sbin statically linked (bad idea) +# +# Variables that control how ppp(8) is built. +#PPP_NO_NAT= # do not build with NAT support (see make.conf(5)) +#PPP_NO_NETGRAPH= # do not build with Netgraph support +#PPP_NO_RADIUS= # do not build with RADIUS support +#PPP_NO_SUID= # build with normal permissions +# +#TRACEROUTE_NO_IPSEC= # do not build traceroute(8) with IPSEC support +# +# To build sys/modules when building the world (our old way of doing things). +#MODULES_WITH_WORLD= # do not build modules when building kernel +# +# The list of modules to build instead of all of them. +#MODULES_OVERRIDE= linux ipfw +# +# The list of modules to never build, applied *after* MODULES_OVERRIDE. +#WITHOUT_MODULES= plip +# +# If you do not want unformatted manual pages to be compressed +# when they are installed: +# +#WITHOUT_MANCOMPRESS=t +# +# +# Default format for system documentation in share/doc, depends on +# your printer. Set this to "ascii" for simple printers or screen. +# +#PRINTERDEVICE= ps +# +# +# How long to wait for a console keypress before booting the default kernel. +# This value is approximately in milliseconds. Keypresses are accepted by the +# BIOS before booting from disk, making it possible to give custom boot +# parameters even when this is set to 0. +# +#BOOTWAIT=0 +#BOOTWAIT=30000 +# +# By default, the system will always use the keyboard/video card as system +# console. However, the boot blocks may be dynamically configured to use a +# serial port in addition to or instead of the keyboard/video console. +# +# By default we use COM1 as our serial console port *if* we're going to use +# a serial port as our console at all. Alter as necessary. +# +# COM1: = 0x3F8, COM2: = 0x2F8, COM3: = 0x3E8, COM4: = 0x2E8 +# +#BOOT_COMCONSOLE_PORT= 0x3F8 +# +# The default serial console speed is 115200. It can be set to a different +# rate, if desired in your environment. +# +#BOOT_COMCONSOLE_SPEED= 9600 +# +# By default the 'pxeboot' loader retrieves the kernel via NFS. Defining +# this and recompiling /usr/src/stand will cause it to retrieve the kernel +# via TFTP. This allows pxeboot to load a custom BOOTP diskless kernel yet +# still mount the server's '/' (i.e. rather than load the server's kernel). +# +#LOADER_TFTP_SUPPORT= YES +# +# +# Kerberos 5 su (k5su) +# If you want to use the k5su utility, define this to have it installed +# set-user-ID. +#ENABLE_SUID_K5SU= +# +# +# top(1) uses a hash table for the user names. The size of this hash +# can be tuned to match the number of local users. The table size should +# be a prime number approximately twice as large as the number of lines in +# /etc/passwd. The default number is 20011. +# +#TOP_TABLE_SIZE= 101 +# +# Documentation +# +# The list of languages to build and install. +# +#DOC_LANG= en ru +# +# +# sendmail +# +# The following sets the default m4 configuration file to use at +# install time. Use with caution as a make install will overwrite +# any existing /etc/mail/sendmail.cf. Note that SENDMAIL_CF is now +# deprecated. The value should be a fully qualified path name. +# +#SENDMAIL_MC=/etc/mail/myconfig.mc +# +# The following sets the default m4 configuration file for mail +# submission to use at install time. Use with caution as a make +# install will overwrite any existing /etc/mail/submit.cf. The +# value should be a fully qualified path name. +# +#SENDMAIL_SUBMIT_MC=/etc/mail/mysubmit.mc +# +# If you need to build additional .cf files during a make buildworld, +# include the full paths to the .mc files in SENDMAIL_ADDITIONAL_MC. +# +#SENDMAIL_ADDITIONAL_MC=/etc/mail/foo.mc /etc/mail/bar.mc +# +# The following overrides the default location for the m4 configuration +# files used to build a .cf file from a .mc file. +# +#SENDMAIL_CF_DIR=/usr/local/share/sendmail/cf +# +# Setting the following variable modifies the flags passed to m4 when +# building a .cf file from a .mc file. It can be used to enable +# features disabled by default. +# +#SENDMAIL_M4_FLAGS= +# +# Setting the following variables modifies the build environment for +# sendmail and its related utilities. For example, SASL support can be +# added with settings such as: +# +# with SASLv1: +# SENDMAIL_CFLAGS=-I/usr/local/include/sasl1 -DSASL +# SENDMAIL_LDADD=/usr/local/lib/libsasl.so +# +# with SASLv2: +# SENDMAIL_CFLAGS=-I/usr/local/include -DSASL=2 +# SENDMAIL_LDADD=/usr/local/lib/libsasl2.so +# +# Note: If you are using Cyrus SASL with other applications which require +# access to the sasldb file, you should add the following to your +# sendmail.mc file: +# +# define(`confDONT_BLAME_SENDMAIL',`GroupReadableSASLDBFile') +# +#SENDMAIL_CFLAGS= +#SENDMAIL_LDFLAGS= +#SENDMAIL_LDADD= +#SENDMAIL_DPADD= +# +# Setting SENDMAIL_SET_USER_ID will install the sendmail binary as a +# set-user-ID root binary instead of a set-group-ID smmsp binary and will +# prevent the installation of /etc/mail/submit.cf. +# This is a deprecated mode of operation. See etc/mail/README for more +# information. +# +#SENDMAIL_SET_USER_ID= +# +# The permissions to use on alias and map databases generated using +# /etc/mail/Makefile. Defaults to 0640. +# +#SENDMAIL_MAP_PERMS= +# +# +# It is also possible to set variables in make.conf which will only be +# used when compiling a specific port. For more details see make(1). +# +#.if ${.CURDIR:M*/irc/irssi-devel*} +#WITH_DEBUG=YES +#.endif +# +# Another approach is to use /usr/ports/ports-mgmt/portconf which has +# its own config file for port specific options. diff --git a/share/examples/find_interface/Makefile b/share/examples/find_interface/Makefile new file mode 100644 index 000000000000..91ce0eb88072 --- /dev/null +++ b/share/examples/find_interface/Makefile @@ -0,0 +1,7 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/${PROG} +PROG= find_interface +MAN= + +.include <bsd.prog.mk> diff --git a/share/examples/find_interface/README b/share/examples/find_interface/README new file mode 100644 index 000000000000..4df4399cdbc7 --- /dev/null +++ b/share/examples/find_interface/README @@ -0,0 +1,9 @@ +This is a simple program which demonstrates how to query the kernel +routing mechanism using only a UDP socket. Pass it a hostname on +the command line (sorry, it doesn't parse dotted decimal) and it will +print out an IP address which names the interface over which UDP +packets intended for that destination would be sent. +A more sophisticated program might use the list obtained from SIOCGIFCONF +to match the address with an interface name, but applications programmers +much more often need to know the address of the interface rather than +the name. diff --git a/share/examples/find_interface/find_interface.c b/share/examples/find_interface/find_interface.c new file mode 100644 index 000000000000..17fe1916d2bd --- /dev/null +++ b/share/examples/find_interface/find_interface.c @@ -0,0 +1,109 @@ +/* + * Copyright 1994, 1995 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This is a simple program which demonstrates how to query the kernel + * routing mechanism using only a UDP socket. Pass it a hostname on + * the command line (sorry, it doesn't parse dotted decimal) and it will + * print out an IP address which names the interface over which UDP + * packets intended for that destination would be sent. + * A more sophisticated program might use the list obtained from SIOCGIFCONF + * to match the address with an interface name, but applications programmers + * much more often need to know the address of the interface rather than + * the name. + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <stdio.h> +#include <netdb.h> +#include <err.h> +#include <errno.h> +#include <string.h> +#include <sysexits.h> + +int +main(int argc, char **argv) +{ + struct sockaddr_in local, remote; + struct hostent *hp; + int s, rv, namelen; + + argc--, argv++; + + if (!*argv) { + errx(EX_USAGE, "must supply a hostname"); + } + + hp = gethostbyname(*argv); + if (!hp) { + errx(EX_NOHOST, "cannot resolve hostname: %s", *argv); + } + + memcpy(&remote.sin_addr, hp->h_addr_list[0], sizeof remote.sin_addr); + remote.sin_port = htons(60000); + remote.sin_family = AF_INET; + remote.sin_len = sizeof remote; + + local.sin_addr.s_addr = htonl(INADDR_ANY); + local.sin_port = htons(60000); + local.sin_family = AF_INET; + local.sin_len = sizeof local; + + s = socket(PF_INET, SOCK_DGRAM, 0); + if (s < 0) + err(EX_OSERR, "socket"); + + do { + rv = bind(s, (struct sockaddr *)&local, sizeof local); + local.sin_port = htons(ntohs(local.sin_port) + 1); + } while(rv < 0 && errno == EADDRINUSE); + + if (rv < 0) + err(EX_OSERR, "bind"); + + do { + rv = connect(s, (struct sockaddr *)&remote, sizeof remote); + remote.sin_port = htons(ntohs(remote.sin_port) + 1); + } while(rv < 0 && errno == EADDRINUSE); + + if (rv < 0) + err(EX_OSERR, "connect"); + + namelen = sizeof local; + rv = getsockname(s, (struct sockaddr *)&local, &namelen); + if (rv < 0) + err(EX_OSERR, "getsockname"); + + printf("Route to %s is out %s\n", *argv, inet_ntoa(local.sin_addr)); + return 0; +} diff --git a/share/examples/flua/libjail.lua b/share/examples/flua/libjail.lua new file mode 100644 index 000000000000..650f0ca2c6a0 --- /dev/null +++ b/share/examples/flua/libjail.lua @@ -0,0 +1,105 @@ +#!/usr/libexec/flua +--[[ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +]]-- + +jail = require("jail") +ucl = require("ucl") + +name = "demo" + +local has_demo = false + +-- Make sure we don't have a demo jail to start with; "jid" and "name" are +-- always present. +for jparams in jail.list() do + if jparams["name"] == name then + has_demo = true + break + end +end + +if not has_demo then + -- Create a persistent jail named "demo" with all other parameters default. + jid, err = jail.setparams(name, {persist = "true"}, jail.CREATE) + if not jid then + error(err) + end +end + +-- Get a list of all known jail parameter names. +allparams = jail.allparams() + +-- Get all the parameters of the jail we created. +jid, res = jail.getparams(name, allparams) +if not jid then + error(res) +end + +-- Display the jail's parameters as a pretty-printed JSON object. +print(ucl.to_json(res)) + +-- Confirm that we still have it for now. +has_demo = false +for jparams in jail.list() do + if jparams["name"] == name then + has_demo = true + break + end +end + +if not has_demo then + print("demo does not exist") +end + +-- Update the "persist" parameter to "false" to remove the jail. +jid, err = jail.setparams(name, {persist = "false"}, jail.UPDATE) +if not jid then + error(err) +end + +-- Verify that the jail is no longer on the system. +local is_persistent = false +has_demo = false +for jparams in jail.list({"persist"}) do + if jparams["name"] == name then + has_demo = true + jid = jparams["jid"] + is_persistent = jparams["persist"] ~= "false" + end +end + +-- In fact, it does remain until this process ends -- c'est la vie. +if has_demo then + io.write("demo still exists, jid " .. jid .. ", ") + if is_persistent then + io.write("persistent\n") + else + io.write("not persistent\n") + end +end diff --git a/share/examples/hast/ucarp.sh b/share/examples/hast/ucarp.sh new file mode 100755 index 000000000000..73253a295f53 --- /dev/null +++ b/share/examples/hast/ucarp.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Pawel Jakub Dawidek under sponsorship from +# the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Shared IP address, unused for now. +addr="10.99.0.3" +# Password for UCARP communication. +pass="password" +# First node IP and interface for UCARP communication. +nodea_srcip="10.99.0.1" +nodea_ifnet="bge0" +# Second node IP and interface for UCARP communication. +nodeb_srcip="10.99.0.2" +nodeb_ifnet="em3" + +export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin + +vhid="1" +upscript="/root/hast/sbin/hastd/vip-up.sh" +downscript="/root/hast/sbin/hastd/vip-down.sh" + +ifconfig "${nodea_ifnet}" 2>/dev/null | grep -q "inet ${nodea_srcip} " +if [ $? -eq 0 ]; then + srcip="${nodea_srcip}" + ifnet="${nodea_ifnet}" + node="node A" +fi +ifconfig "${nodeb_ifnet}" 2>/dev/null | grep -q "inet ${nodeb_srcip} " +if [ $? -eq 0 ]; then + if [ -n "${srcip}" -o -n "${ifnet}" ]; then + echo "Unable to determine which node is this (both match)." >/dev/stderr + exit 1 + fi + srcip="${nodeb_srcip}" + ifnet="${nodeb_ifnet}" + node="node B" +fi +if [ -z "${srcip}" -o -z "${ifnet}" ]; then + echo "Unable to determine which node is this (none match)." >/dev/stderr + exit 1 +fi +ucarp -i ${ifnet} -s ${srcip} -v ${vhid} -a ${addr} -p ${pass} -u "${upscript}" -d "${downscript}" diff --git a/share/examples/hast/ucarp_down.sh b/share/examples/hast/ucarp_down.sh new file mode 100755 index 000000000000..133d35c59d5b --- /dev/null +++ b/share/examples/hast/ucarp_down.sh @@ -0,0 +1,99 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Pawel Jakub Dawidek under sponsorship from +# the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Resource name as defined in /etc/hast.conf. +resource="test" +# Supported file system types: UFS, ZFS +fstype="UFS" +# ZFS pool name. Required only when fstype == ZFS. +pool="test" +# File system mount point. Required only when fstype == UFS. +mountpoint="/mnt/test" +# Name of HAST provider as defined in /etc/hast.conf. +# Required only when fstype == UFS. +device="/dev/hast/${resource}" + +export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin + +# KIll UP script if it still runs in the background. +sig="TERM" +for i in `jot 30`; do + pgid=`pgrep -f ucarp_up.sh | head -1` + [ -n "${pgid}" ] || break + kill -${sig} -- -${pgid} + sig="KILL" + sleep 1 +done +if [ -n "${pgid}" ]; then + logger -p local0.error -t hast "UCARP UP process for resource ${resource} is still running after 30 seconds." + exit 1 +fi +logger -p local0.debug -t hast "UCARP UP is not running." + +case "${fstype}" in +UFS) + mount | egrep -q "^${device} on " + if [ $? -eq 0 ]; then + # Forcibly unmount file system. + out=`umount -f "${mountpoint}" 2>&1` + if [ $? -ne 0 ]; then + logger -p local0.error -t hast "Unable to unmount file system for resource ${resource}: ${out}." + exit 1 + fi + logger -p local0.debug -t hast "File system for resource ${resource} unmounted." + fi + ;; +ZFS) + zpool list | egrep -q "^${pool} " + if [ $? -eq 0 ]; then + # Forcibly export file pool. + out=`zpool export -f "${pool}" 2>&1` + if [ $? -ne 0 ]; then + logger -p local0.error -t hast "Unable to export pool for resource ${resource}: ${out}." + exit 1 + fi + logger -p local0.debug -t hast "ZFS pool for resource ${resource} exported." + fi + ;; +esac + +# Change role to secondary for our resource. +out=`hastctl role secondary "${resource}" 2>&1` +if [ $? -ne 0 ]; then + logger -p local0.error -t hast "Unable to change to role to secondary for resource ${resource}: ${out}." + exit 1 +fi +logger -p local0.debug -t hast "Role for resource ${resource} changed to secondary." + +logger -p local0.info -t hast "Successfully switched to secondary for resource ${resource}." + +exit 0 diff --git a/share/examples/hast/ucarp_up.sh b/share/examples/hast/ucarp_up.sh new file mode 100755 index 000000000000..9f22b4205909 --- /dev/null +++ b/share/examples/hast/ucarp_up.sh @@ -0,0 +1,106 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Pawel Jakub Dawidek under sponsorship from +# the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Resource name as defined in /etc/hast.conf. +resource="test" +# Supported file system types: UFS, ZFS +fstype="UFS" +# ZFS pool name. Required only when fstype == ZFS. +pool="test" +# File system mount point. Required only when fstype == UFS. +mountpoint="/mnt/test" +# Name of HAST provider as defined in /etc/hast.conf. +device="/dev/hast/${resource}" + +export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin + +# If there is secondary worker process, it means that remote primary process is +# still running. We have to wait for it to terminate. +for i in `jot 30`; do + pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1 || break + sleep 1 +done +if pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1; then + logger -p local0.error -t hast "Secondary process for resource ${resource} is still running after 30 seconds." + exit 1 +fi +logger -p local0.debug -t hast "Secondary process in not running." + +# Change role to primary for our resource. +out=`hastctl role primary "${resource}" 2>&1` +if [ $? -ne 0 ]; then + logger -p local0.error -t hast "Unable to change to role to primary for resource ${resource}: ${out}." + exit 1 +fi +# Wait few seconds for provider to appear. +for i in `jot 50`; do + [ -c "${device}" ] && break + sleep 0.1 +done +if [ ! -c "${device}" ]; then + logger -p local0.error -t hast "Device ${device} didn't appear." + exit 1 +fi +logger -p local0.debug -t hast "Role for resource ${resource} changed to primary." + +case "${fstype}" in +UFS) + # Check the file system. + fsck -y -t ufs "${device}" >/dev/null 2>&1 + if [ $? -ne 0 ]; then + logger -p local0.error -t hast "File system check for resource ${resource} failed." + exit 1 + fi + logger -p local0.debug -t hast "File system check for resource ${resource} finished." + # Mount the file system. + out=`mount -t ufs "${device}" "${mountpoint}" 2>&1` + if [ $? -ne 0 ]; then + logger -p local0.error -t hast "File system mount for resource ${resource} failed: ${out}." + exit 1 + fi + logger -p local0.debug -t hast "File system for resource ${resource} mounted." + ;; +ZFS) + # Import ZFS pool. Do it forcibly as it remembers hostid of + # the other cluster node. + out=`zpool import -f "${pool}" 2>&1` + if [ $? -ne 0 ]; then + logger -p local0.error -t hast "ZFS pool import for resource ${resource} failed: ${out}." + exit 1 + fi + logger -p local0.debug -t hast "ZFS pool for resource ${resource} imported." + ;; +esac + +logger -p local0.info -t hast "Successfully switched to primary for resource ${resource}." + +exit 0 diff --git a/share/examples/hast/vip-down.sh b/share/examples/hast/vip-down.sh new file mode 100755 index 000000000000..d4a6eed24f0d --- /dev/null +++ b/share/examples/hast/vip-down.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +/root/hast/sbin/hastd/ucarp_down.sh +exit 0 diff --git a/share/examples/hast/vip-up.sh b/share/examples/hast/vip-up.sh new file mode 100755 index 000000000000..84b6e6a94100 --- /dev/null +++ b/share/examples/hast/vip-up.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +set -m +/root/hast/sbin/hastd/ucarp_up.sh & +set +m +exit 0 diff --git a/share/examples/hwpmc/Makefile b/share/examples/hwpmc/Makefile new file mode 100644 index 000000000000..fcbb6160bb00 --- /dev/null +++ b/share/examples/hwpmc/Makefile @@ -0,0 +1,10 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/hwpmc +PROG= overhead +LDFLAGS+= -lpmc +MAN= + +install: + +.include <bsd.prog.mk> diff --git a/share/examples/hwpmc/README b/share/examples/hwpmc/README new file mode 100644 index 000000000000..f94ef2c7ecdd --- /dev/null +++ b/share/examples/hwpmc/README @@ -0,0 +1,5 @@ + +Examples illustrating the use of the hwpmc(4) driver and pmc(3) +library interface. + + diff --git a/share/examples/hwpmc/overhead.c b/share/examples/hwpmc/overhead.c new file mode 100644 index 000000000000..bf8e060ef5b6 --- /dev/null +++ b/share/examples/hwpmc/overhead.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2014, Neville-Neil Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: George V. Neville-Neil + * + */ + +/* + * Calculate the time overhead of starting, stopping, and recording + * pmc counters. + * + * The only argument is a counter name, such as "instruction-retired" + * which is CPU dependent and can be found with pmmcontrol(8) using + * pmccontrol -L. + * + * The start, stop, read and write operations are timed using the + * rdtsc() macro which reads the Time Stamp Counter on the CPU. + */ + +#include <stdio.h> +#include <err.h> +#include <sysexits.h> +#include <sys/types.h> +#include <machine/cpufunc.h> +#include <pmc.h> + +int +main(int argc, char **argv) +{ + pmc_id_t pmcid; + pmc_value_t read_value; + pmc_value_t read_clear_value; + uint64_t tsc1, write_cyc, start_cyc, read_cyc, stop_cyc; + char *counter_name; + + if (argc != 2) + err(EX_USAGE, "counter-name required"); + + counter_name = argv[1]; + + if (pmc_init() != 0) + err(EX_OSERR, "hwpmc(4) not loaded, kldload or update your kernel"); + + if (pmc_allocate(counter_name, PMC_MODE_SC, 0, 0, &pmcid, 64*1024) < 0) + err(EX_OSERR, "failed to allocate %s as a system counter in counting mode", + counter_name); + + tsc1 = rdtsc(); + if (pmc_write(pmcid, 0) < 0) + err(EX_OSERR, "failed to zero counter %s", counter_name); + write_cyc = rdtsc() - tsc1; + + tsc1 = rdtsc(); + if (pmc_start(pmcid) < 0) + err(EX_OSERR, "failed to start counter %s", counter_name); + start_cyc = rdtsc() - tsc1; + + tsc1 = rdtsc(); + if (pmc_read(pmcid, &read_value) < 0) + err(EX_OSERR, "failed to read counter %s", counter_name); + read_cyc = rdtsc() - tsc1; + + tsc1 = rdtsc(); + if (pmc_stop(pmcid) < 0) + err(EX_OSERR, "failed to stop counter %s", counter_name); + stop_cyc = rdtsc() - tsc1; + + if (pmc_rw(pmcid, 0, &read_clear_value)) + err(EX_OSERR, "failed to read and zero %s", counter_name); + + if (pmc_release(pmcid) < 0) + err(EX_OSERR, "failed to release %s as a system counter in counting mode", + counter_name); + + printf("Counter %s, read value %ld, read/clear value %ld\n", + counter_name, read_value, read_clear_value); + printf("Cycles to start: %ld\tstop: %ld\tread: %ld\twrite: %ld\n", + start_cyc, stop_cyc, read_cyc, stop_cyc); + + return(0); +} + diff --git a/share/examples/indent/indent.pro b/share/examples/indent/indent.pro new file mode 100644 index 000000000000..c85bfda3f4bc --- /dev/null +++ b/share/examples/indent/indent.pro @@ -0,0 +1,46 @@ +-TFILE +-Tfd_mask +-Tfd_set +-Tlinker_sym_tT +-Tu_char +-Tu_int +-Tu_long +-Tu_short +-TTAILQ_HEAD +-TTAILQ_ENTRY +-TLIST_HEAD +-TLIST_ENTRY +-TSTAILQ_HEAD +-TSTAILQ_ENTRY +-TSLIST_HEAD +-TSLIST_ENTRY +-bad +-bap +-nbbb +-nbc +-br +-nbs +-c41 +-cd41 +-cdb +-ce +-ci4 +-cli0 +-d0 +-di8 +-ndj +-ei +-nfc1 +-nfcb +-i8 +-ip8 +-l79 +-lc77 +-ldi0 +-nlp +-npcs +-psl +-sc +-nsob +-ta +-nv diff --git a/share/examples/ipfilter/BNF b/share/examples/ipfilter/BNF new file mode 100644 index 000000000000..ef35d25e9f8a --- /dev/null +++ b/share/examples/ipfilter/BNF @@ -0,0 +1,81 @@ +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . + +insert = "@" decnumber . +action = block | "pass" | log | "count" | auth | call . +in-out = "in" | "out" . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . + +onif = "on" interface-name [ "out-via" interface-name ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . +tag = "tag" tagid . +call = "call" [ "now" ] function-name "/" decnumber. +dup = "dup-to" interface-name[":"ipaddr] . +froute = "fastroute" | "to" interface-name . +replyto = "reply-to" interface-name [ ":" ipaddr ] . +protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . +srcdst = "all" | fromto . +fromto = "from" object "to" object . + +return-icmp = "return-icmp" | "return-icmp-as-dest" . +loglevel = facility"."priority | priority . +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . +flags = "flags" flag { flag } [ "/" flag { flag } ] . +with = "with" | "and" . +icmp = "icmp-type" icmp-type [ "code" decnumber ] . +return-code = "("icmp-code")" . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . + +nummask = host-name [ "/" decnumber ] . +host-name = ipaddr | hostname | "any" . +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . +port-num = service-name | decnumber . + +withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . +optname = ipopts [ "," optname ] . +ipopts = optlist | "sec-class" [ secname ] . +secname = seclvl [ "," secname ] . +seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" | + "reserv-4" | "secret" | "topsecret" . +icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | + "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | + "inforep" | "maskreq" | "maskrep" | "routerad" | + "routersol" | decnumber . +icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | + "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | + "visa" | "imitd" | "eip" | "finn" . +facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" | + "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" | + "audit" | "logalert" | "local0" | "local1" | "local2" | + "local3" | "local4" | "local5" | "local6" | "local7" . +priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | + "info" | "debug" . + +hexnumber = "0" "x" hexstring . +hexstring = hexdigit [ hexstring ] . +decnumber = digit [ decnumber ] . + +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | + "le" | "ge" . +range = "<>" | "><" . +hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/share/examples/ipfilter/Makefile b/share/examples/ipfilter/Makefile new file mode 100644 index 000000000000..b1b8b57449f1 --- /dev/null +++ b/share/examples/ipfilter/Makefile @@ -0,0 +1,31 @@ + +PACKAGE=ipf +FILES= README + +# dist sample files +.PATH: ${.CURDIR}/rules +FILES+= BASIC.NAT BASIC_1.FW BASIC_2.FW \ + example.1 example.2 example.3 example.4 example.5 \ + example.6 example.7 example.8 example.9 example.10 \ + example.11 example.12 example.13 example.sr firewall \ + ftp-proxy ftppxy nat-setup nat.eg server tcpstate + +# ftp://ftp.OpenBSD.org/pub/OpenBSD/src/share/ipf/ sample files. +FILES+= example.14 firewall.1 firewall.2 \ + ipf.conf.permissive ipf.conf.restrictive \ + ipf.conf.sample ipnat.conf.sample + +# http://www.obfuscation.org/ipf/ how-to +FILES+= ipf-howto.txt + +# http://coombs.anu.edu.au/~avalon/ sample files +FILES+= examples.txt rules.txt + +BINMODE=0755 +SCRIPTS= mkfilters +MAN= mkfilters.1 + +SCRIPTSDIR= ${SHAREDIR}/examples/ipfilter +FILESDIR= ${SHAREDIR}/examples/ipfilter + +.include <bsd.prog.mk> diff --git a/share/examples/ipfilter/Makefile.depend b/share/examples/ipfilter/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/ipfilter/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/ipfilter/README b/share/examples/ipfilter/README new file mode 100644 index 000000000000..aa4df9786702 --- /dev/null +++ b/share/examples/ipfilter/README @@ -0,0 +1,14 @@ + +This directory contains various files related to ipfilter. + +For information on building ipf based firewalls, read the ipf-howto.txt. + +a more up to date version of this file may be found at: + + http://www.obfuscation.org/ipf/ + +Additional help may be found at the ipf home page: + + http://coombs.anu.edu.au/~avalon/ + +examples.txt and rules.txt come from this site. diff --git a/share/examples/ipfilter/example.14 b/share/examples/ipfilter/example.14 new file mode 100644 index 000000000000..c4c1994030ba --- /dev/null +++ b/share/examples/ipfilter/example.14 @@ -0,0 +1,61 @@ +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 diff --git a/share/examples/ipfilter/examples.txt b/share/examples/ipfilter/examples.txt new file mode 100644 index 000000000000..2faf50a16a0b --- /dev/null +++ b/share/examples/ipfilter/examples.txt @@ -0,0 +1,514 @@ +IP Filter Examples + + [Image] Permissions + [Image] Interface + [Image] Netmasks and hosts + [Image] IP Protocols + [Image] IP Options + [Image] IP Fragments + [Image] TCP/UDP Ports + [Image] ICMP type/code + [Image] TCP Flags (established) + [Image] Responding to a BAD packet + [Image] IP Security Classes + [Image] Packet state filtering + [Image] Network Address Translation (NAT) + [Image] Transparent Proxy Support + [Image] Transparent routing + [Image] Logging packets to network devices + [Image] Rule groups + Authenticating packets + Pre-authenticating packets + + ------------------------------------------------------------------------ + +Permission Specifying. + +To specify where to pass through or to block a packet, either block or pass +is used. In and out are used to describe the direction in which the packet +is travelling through a network interface. Eg: + +# setup default to block all packets. +block in all +block out all +# pass packets from host firewall to any destination +pass in from firewall to any + + ------------------------------------------------------------------------ + +Select network Interfaces + +To select which interface a packet is currently associated with, either its +destination as a result of route processing or where it has been received +from, the on keyword is used. Whilst not compulsory, it is recommended that +each rule include it for clarity. Eg: + +# drop all inbound packets from localhost coming from ethernet +block in on le0 from localhost to any + + ------------------------------------------------------------------------ + +Netmasks and hosts + +As not all networks are formed with classical network boundaries, it is +necessary to provide a mechanism to support VLSM (Variable Length Subnet +Masks). This package provides several ways to do this. Eg: + +# +block in on le0 from mynet/26 to any +# +block in on le0 from mynet/255.255.255.192 to any +# +block in on le0 from mynet mask 255.255.255.192 to any +# +block in on le0 from mynet mask 0xffffffc0 to any + +Are all valid and legal syntax with this package. However, when regenerating +rules (ie using ipfstat), this package will prefer to use the shortest valid +notation (top down). + +The default netmask, when none is given is 255.255.255.255 or "/32". + +To invert the match on a hostname or network, include an ! before the name +or number with no space between them. + ------------------------------------------------------------------------ + +Protocol + +To filter on an individual protocol, it is possible to specify the protocol +in a filter rule. Eg: + +# block all incoming ICMP packets +block in on le0 proto icmp all + +The name of the protocol can be any valid name from /etc/protocols or a +number. + +# allow all IP packets in which are protocol 4 +pass in on le0 proto 4 all + +There is one exception to this rule, being "tcp/udp". If given in a ruleset, +it will match either of the two protocols. This is useful when setting up +port restrictions. Eg: + +# prevent any packets destined for NFS from coming in +block in on le0 proto tcp/udp from any to any port = 2049 + + ------------------------------------------------------------------------ + +Filtering IP fragments + +IP fragments are bad news, in general. Recent study has shown that IP +fragments can pose a large threat to IP packet filtering, IF there are rules +used which rely on data which may be distributed across fragments. To this +package, the threat is that the TCP flags field of the TCP packet may be in +the 2nd or 3rd fragment or possibly be believed to be in the first when +actually in the 2nd or 3rd. + +To filter out these nasties, it is possible to select fragmented packets out +as follows: + +# +# get rid of all IP fragments +# +block in all with frag + +The problem arises that fragments can actually be a non-malicious. The +really malicious ones can be grouped under the term "short fragments" and +can be filtered out as follows: + +# +# get rid of all short IP fragments (too small for valid comparison) +# +block in proto tcp all with short + + ------------------------------------------------------------------------ + +IP Options + +IP options have a bad name for being a general security threat. They can be +of some use, however, to programs such as traceroute but many find this +usefulness not worth the risk. + +Filtering on IP options can be achieved two ways. The first is by naming +them collectively and is done as follows: + +# +# drop and log any IP packets with options set in them. +# +block in log all with ipopts +# + +The second way is to actually list the names of the options you wish to +filter. + +# +# drop any source routing options +# +block in quick all with opt lsrr +block in quick all with opt ssrr + +[Image] NOTE that options are matched explicitly, so if I had lsrr,ssrr it +would only match packets with both options set. + +It is also possible to select packets which DON'T have various options +present in the packet header. For example, to allow telnet connections +without any IP options present, the following would be done: + +# +# Allow anyone to telnet in so long as they don't use IP options. +# +pass in proto tcp from any to any port = 23 with no ipopts +# +# Allow packets with strict source routing and no loose source routing +# +pass in from any to any with opt ssrr not opt lsrr + + ------------------------------------------------------------------------ + +Filtering by ports + +Filtering by port number only works with the TCP and UDP IP protocols. When +specifying port numbers, either the number or the service name from +/etc/services may be used. If the proto field is used in a filter rule, it +will be used in conjunction with the port name in determining the port +number. + +The possible operands available for use with port numbers are: + +Operand Alias Parameters Result +< lt port# true if port is less than given value +> gt port# true if port is greater than given value += eq port# true if port is equal to than given value +!= ne port# true if port is not equal to than given value +<= le port# true if port is less than or equal to given value +=> ge port# true if port is greater than or equal to given value + +Eg: + +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from fubar/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from fubar port != 53 to localhost + +Two range comparisons are also possible: + +Expression Syntax: +port1# <> port2# true if port is less than port1 or greater than port2 +port1# >< port2# true if port is greater than port1 and less than port2 + +[Image] NOTE that in neither case, when the port number is equal to one of +those given, does it match. Eg: + +# +# block anything trying to get to X terminal ports, X:0 to X:9 +# +block in proto tcp from any to any port 5999 >< 6010 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +block in proto tcp/udp all +pass in proto tcp/udp from any to any port 512 <> 515 + +Note that the last one above could just as easily be done in the reverse +fashion: allowing everything through and blocking only a small range. Note +that the port numbers are different, however, due to the difference in the +way they are compared. + +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +pass in proto tcp/udp all +block in proto tcp/udp from any to any port 511 >< 516 + + ------------------------------------------------------------------------ + +TCP Flags (established) + +Filtering on TCP flags is useful, but fraught with danger. I'd recommend +that before using TCP flags in your IP filtering, you become at least a +little bit acquainted with what the role of each of them is and when they're +used. This package will compare the flags present in each TCP packet, if +asked, and match if those present in the TCP packet are the same as in the +IP filter rule. + +Some IP filtering/firewall packages allow you to filter out TCP packets +which belong to an "established" connection. This is, simply put, filtering +on packets which have the ACK bit set. The ACK bit is only set in packets +transmitted during the lifecycle of a TCP connection. It is necessary for +this flag to be present from either end for data to be transferred. If you +were using a rule which as worded something like: + +allow proto tcp 10.1.0.0 255.255.0.0 port = 23 10.2.0.0 255.255.0.0 established + +It could be rewritten as: + +pass in proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A +pass out proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A + +A more useful flag to filter on, for TCP connections, I find, is the SYN +flag. This is only set during the initial stages of connection negotiation, +and for the very first packet of a new TCP connection, it is the only flag +set. At all other times, an ACK or maybe even an URG/PUSH flag may be set. +So, if I want to stop connections being made to my internal network +(10.1.0.0) from the outside network, I might do something like: + +# +# block incoming connection requests to my internal network from the big bad +# internet. +# +block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA + +If you wanted to block the replies to this (the SYN-ACK's), then you might +do: + +block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA + +where SA represents the SYN-ACK flags both being set. + +The flags after the / represent the TCP flag mask, indicating which bits of +the TCP flags you are interested in checking. When using the SYN bit in a +check, you SHOULD specify a mask to ensure that your filter CANNOT be +defeated by a packet with SYN and URG flags, for example, set (to Unix, this +is the same as a plain SYN). + ------------------------------------------------------------------------ + +ICMP Type/Code + +ICMP can be a source of a lot of trouble for Internet Connected networks. +Blocking out all ICMP packets can be useful, but it will disable some +otherwise useful programs, such as "ping". Filtering on ICMP type allows for +pings (for example) to work. Eg: + +# block all ICMP packets. +# +block in proto icmp all +# +# allow in ICMP echos and echo-replies. +# +pass in on le1 proto icmp from any to any icmp-type echo +pass in on le1 proto icmp from any to any icmp-type echorep + +To specify an ICMP code, the numeric value must be used. So, if we wanted to +block all port-unreachables, we would do: + +# +# block all ICMP destination unreachable packets which are port-unreachables +# +block in on le1 proto icmp from any to any icmp-type unreach code 3 + + ------------------------------------------------------------------------ + +Responding to a BAD packet + +To provide feedback to people trying to send packets through your filter +which you wish to disallow, you can send back either an ICMP error +(Destination Unreachable) or, if they're sending a TCP packet, a TCP RST +(Reset). + +What's the difference ? TCP/IP stacks take longer to pass the ICMP errors +back, through to the application, as they can often be due to temporary +problems (network was unplugged for a second) and it is `incorrect' to shut +down a connection for this reason. Others go to the other extreme and will +shut down all connections between the two hosts for which the ICMP error is +received. The TCP RST, however, is for only *one* connection (cannot be used +for more than one) and will cause the connection to immediately shut down. +So, for example, if you're blocking port 113, and setup a rule to return a +TCP RST rather than nothing or an ICMP packet, you won't experience any +delay if the other end was attempting to make a connection to an identd +service. + +Some examples are as follows: + +# +# block all incoming TCP connections but send back a TCP-RST for ones to +# the ident port +# +block in proto tcp from any to any flags S/SA +block return-rst in quick proto tcp from any to any port = 113 flags S/SA +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp in proto udp from any to any + +When returning ICMP packets, it is also possible to specify the type of ICMP +error return. This was requested so that traceroute traces could be forced +to end elegantly. To do this, the requested ICMP Unreachable code is placed +in brackets following the "return-icmp" directive: + +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp (3) in proto udp from any to any port > 30000 +block return-icmp (port-unr) in proto udp from any to any port > 30000 + +Those two examples are equivalent, and return an ICMP port unreachable error +packet to in response to any UDP packet received destined for a port greater +than 30,000. + ------------------------------------------------------------------------ + +Filtering IP Security Classes + +For users who have packets which contain IP security bits, filtering on the +defined classes and authority levels is supported. Currently, filtering on +16bit authority flags is not supported. + +As with ipopts and other IP options, it is possible to say that the packet +only matches if a certain class isn't present. + +Some examples of filtering on IP security options: + +# +# drop all packets without IP security options +# +block in all with no opt sec +# +# only allow packets in and out on le0 which are top secret +# +block out on le1 all +pass out on le1 all with opt sec-class topsecret +block in on le1 all +pass in on le1 all with opt sec-class topsecret + + ------------------------------------------------------------------------ + +Packet state filtering + +Packet state filtering can be used for any TCP flow to short-cut later +filtering. The "short-cuts" are kept in a table, with no alterations to the +packet filter list made. Subsequent packets, if a matching packet is found +in the table, are not passed through the list. For TCP flows, the filter +will follow the ack/sequence numbers of packets and only allow packets +through which fall inside the correct window. + +# +# Keep state for all outgoing telnet connections +# and disallow all other TCP traffic. +# +pass out on le1 proto tcp from any to any port = telnet keep state +block out on le1 all + +For UDP packets, packet exchanges are effectively stateless. However, if a +packet is first sent out from a given port, a reply is usually expected in +answer, in the `reverse' direction. + +# +# allow UDP replies back from name servers +# +pass out on le1 proto udp from any to any port = domain keep state + +Held UDP state is timed out, as is TCP state for entries added which do not +have the SYN flag set. If an entry is created with the SYN flag set, any +subsequent matching packet which doesn't have this flag set (ie a SYN-ACK) +will cause it to be "timeless" (actually, the timeout defaults to 5 days), +until either a FIN or RST is seen. + + ------------------------------------------------------------------------ + +Network Address Translation (NAT) + +Network address translation is used to remap IP #'s from one address range +to another range of network addresses. For TCP and UDP, this also can +include the port numbers. The IP#'s/port #'s are changed when a packet is +going out through an interface and IP Filter matches it against a NAT rules. + +Packets coming back in the same interface are remapped, as a matter of +course, to their original address information. + +# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source +# port number to something between 10,000 and 20,000 inclusive. For all other +# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily +# for each new user. In this example, ed1 is the external interface. +# Use ipnat, not ipf to load these rules. +# +map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000 +map ed1 10.1.0.0/16 -> 240.1.0.0/24 + + ------------------------------------------------------------------------ + +Transparent Proxy Suppoer + +Transparent proxies are supported through redirection, which works in a +similar way to NAT, except that rules are triggered by input packets. To +effect redirection rules, ipnat must be used (same as for NAT) rather than +ipf. + +# Redirection is triggered for input packets. +# For example, to redirect FTP connections through this box (in this case ed0 +# is the interface on the "inside" where default routes point), to the local +# ftp port, forcing them to connect through a proxy, you would use: +# +rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp + + ------------------------------------------------------------------------ + +Transparent routing + +Transparent routing can be performed in two ways using IP Filter. The first +is to use the keyword "fastroute" in a rule, using the normal route lookup +to occur or using a fixed route with "to". Both effect transparent routing +by not causing any decrement in the TTL to occur as it passes through the +kernel. + +# Route all UDP packets through transparently. +# +pass in quick fastroute proto udp all +# +# Route all ICMP packets to network 10 (on le0) out through le1, to "router" +# +pass in quick on le0 to le1:router proto icmp all + + ------------------------------------------------------------------------ + +Logging packets to the network + +Logging packets to the network devices is supported for both packets being +passed through the filter and those being blocked. For packets being passed +on, the "dup-to" keyword must be used, but for packets being blocked, either +"to" (more efficient) or "dup-to" can be used. + +To log packets to the interface without requiring ARP to work, create a +static arp cache for a meaningless IP# (say 10.0.0.1) and log packets to +this IP#. + +# Log all short TCP packets to qe3, with "packetlog" as the intended +# destination for the packet. +# +block in quick to qe3:packetlog proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in quick on ppp0 dup-to le1:packetlog proto tcp all flags S/SA + + ------------------------------------------------------------------------ + +Rule groups + +To aide in making rule processing more efficient, it is possible to setup +rule `groups'. By default, all rules are in group 0 and all other groups +have it as their ultimate parent. To start a new group, a rule includes a +`head' statement, such as this: + +# Process all incoming ppp packets on ppp0 with group 100, with the default for +# this interface to block all incoming. +# +block in quick on ppp0 all head 100 + +If we then wanted to allow people to connect to our WWW server, via ppp0, we +could then just add a rule about WWW. NOTE: only packets which match the +above rule are processed by any group 100 rules. + +# Allow connections to the WWW server via ppp0. +# +pass in quick proto tcp from any to any port = WWW keep state group 100 + + ------------------------------------------------------------------------ +Return to the IP Filter home page diff --git a/share/examples/ipfilter/firewall.1 b/share/examples/ipfilter/firewall.1 new file mode 100644 index 000000000000..077a4607b192 --- /dev/null +++ b/share/examples/ipfilter/firewall.1 @@ -0,0 +1,35 @@ +# +# This is an example of a very light firewall used to guard against +# some of the most easily exploited common security holes. +# +# The example assumes it is running on a gateway with interface ppp0 +# attached to the outside world, and interface ed0 attached to +# network 192.168.4.0 which needs to be protected. +# +# +# Pass any packets not explicitly mentioned by subsequent rules +# +pass out from any to any +pass in from any to any +# +# Block any inherently bad packets coming in from the outside world. +# These include ICMP redirect packets and IP fragments so short the +# filtering rules won't be able to examine the whole UDP/TCP header. +# +block in log quick on ppp0 proto icmp from any to any icmp-type redir +block in log quick on ppp0 proto tcp/udp all with short +# +# Block any IP spoofing attempts. (Packets "from" our network +# shouldn't be coming in from outside). +# +block in log quick on ppp0 from 192.168.4.0/24 to any +block in log quick on ppp0 from localhost to any +block in log quick on ppp0 from 0.0.0.0/32 to any +block in log quick on ppp0 from 255.255.255.255/32 to any +# +# Block any incoming traffic to NFS ports, to the RPC portmapper, and +# to X servers. +# +block in log on ppp0 proto tcp/udp from any to any port = sunrpc +block in log on ppp0 proto tcp/udp from any to any port = 2049 +block in log on ppp0 proto tcp from any to any port = 6000 diff --git a/share/examples/ipfilter/firewall.2 b/share/examples/ipfilter/firewall.2 new file mode 100644 index 000000000000..d87721088afc --- /dev/null +++ b/share/examples/ipfilter/firewall.2 @@ -0,0 +1,69 @@ +# +# This is an example of a fairly heavy firewall used to keep everyone +# out of a particular network while still allowing people within that +# network to get outside. +# +# The example assumes it is running on a gateway with interface ppp0 +# attached to the outside world, and interface ed0 attached to +# network 192.168.4.0 which needs to be protected. +# +# +# Pass any packets not explicitly mentioned by subsequent rules +# +pass out from any to any +pass in from any to any +# +# Block any inherently bad packets coming in from the outside world. +# These include ICMP redirect packets, IP fragments so short the +# filtering rules won't be able to examine the whole UDP/TCP header, +# and anything with IP options. +# +block in log quick on ppp0 proto icmp from any to any icmp-type redir +block in log quick on ppp0 proto tcp/udp all with short +block in log quick on ppp0 from any to any with ipopts +# +# Block any IP spoofing attempts. (Packets "from" our network +# shouldn't be coming in from outside). +# +block in log quick on ppp0 from 192.168.4.0/24 to any +block in log quick on ppp0 from localhost to any +block in log quick on ppp0 from 0.0.0.0/32 to any +block in log quick on ppp0 from 255.255.255.255/32 to any +# +# Block all incoming UDP traffic except talk and DNS traffic. NFS +# and portmap are special-cased and logged. +# +block in on ppp0 proto udp from any to any +block in log on ppp0 proto udp from any to any port = sunrpc +block in log on ppp0 proto udp from any to any port = 2049 +pass in on ppp0 proto udp from any to any port = domain +pass in on ppp0 proto udp from any to any port = talk +pass in on ppp0 proto udp from any to any port = ntalk +# +# Block all incoming TCP traffic connections to known services, +# returning a connection reset so things like ident don't take +# forever timing out. Don't log ident (auth port) as it's so common. +# +block return-rst in log on ppp0 proto tcp from any to any flags S/SA +block return-rst in on ppp0 proto tcp from any to any port = auth flags S/SA +# +# Allow incoming TCP connections to ports between 1024 and 5000, as +# these don't have daemons listening but are used by outgoing +# services like ftp and talk. For slightly more obscurity (though +# not much more security), the second commented out rule can chosen +# instead. +# +pass in on ppp0 proto tcp from any to any port 1024 >< 5000 +#pass in on ppp0 proto tcp from any port = ftp-data to any port 1024 >< 5000 +# +# Now allow various incoming TCP connections to particular hosts, TCP +# to the main nameserver so secondaries can do zone transfers, SMTP +# to the mail host, www to the web server (which really should be +# outside the firewall if you care about security), and ssh to a +# hypothetical machine caled 'gatekeeper' that can be used to gain +# access to the protected network from the outside world. +# +pass in on ppp0 proto tcp from any to ns1 port = domain +pass in on ppp0 proto tcp from any to mail port = smtp +pass in on ppp0 proto tcp from any to www port = www +pass in on ppp0 proto tcp from any to gatekeeper port = ssh diff --git a/share/examples/ipfilter/ipf-howto.txt b/share/examples/ipfilter/ipf-howto.txt new file mode 100644 index 000000000000..66f67bd96bf1 --- /dev/null +++ b/share/examples/ipfilter/ipf-howto.txt @@ -0,0 +1,3167 @@ + + + + + + + IP Filter Based Firewalls HOWTO + + Brendan Conoboy <synk@swcp.com> + Erik Fichtner <emf@obfuscation.org> + + Fri Apr 20 09:31:14 EDT 2001 + + + + + + + Abstract: This document is intended to introduce a new + user to the IP Filter firewalling package and, at the + same time, teach the user some basic fundamentals of + good firewall design. + + + + + + + + + + + + +1. Introduction + + IP Filter is a great little firewall package. It does +just about everything other free firewalls (ipfwadm, +ipchains, ipfw) do, but it's also portable and does neat +stuff the others don't. This document is intended to make +some cohesive sense of the sparse documentation presently +available for ipfilter. Some prior familiarity with packet +filtering will be useful, however too much familiarity may +make this document a waste of your time. For greater under- +standing of firewalls, the authors recommend reading Build- +ing Internet Firewalls, Chapman & Zwicky, O'Reilly and Asso- +ciates; and TCP/IP Illustrated, Volume 1, Stevens, Addison- +Wesley. + + + + + +1.1. Disclaimer + + The authors of this document are not responsible for +any damages incurred due to actions taken based on this doc- +ument. This document is meant as an introduction to building +a firewall based on IP-Filter. If you do not feel + + + + + + + + + + -2- + + +comfortable taking responsibility for your own actions, you +should stop reading this document and hire a qualified secu- +rity professional to install your firewall for you. + + +1.2. Copyright + + Unless otherwise stated, HOWTO documents are copy- +righted by their respective authors. HOWTO documents may be +reproduced and distributed in whole or in part, in any +medium physical or electronic, as long as this copyright +notice is retained on all copies. Commercial redistribution +is allowed and encouraged; however, the authors would like +to be notified of any such distributions. + + All translations, derivative works, or aggregate works +incorporating any HOWTO documents must be covered under this +copyright notice. That is, you may not produce a derivative +work from a HOWTO and impose additional restrictions on its +distribution. Exceptions to these rules may be granted under +certain conditions; please contact the HOWTO coordinator. + + In short, we wish to promote dissemination of this +information through as many channels as possible. However, +we do wish to retain copyright on the HOWTO documents, and +would like to be notified of any plans to redistribute the +HOWTOs. + + +1.3. Where to obtain the important pieces + + The official IPF homepage is at: +<http://coombs.anu.edu.au/~avalon/ip-filter.html> + + The most up-to-date version of this document can be +found at: <http://www.obfuscation.org/ipf/> + + + + +2. Basic Firewalling + + This section is designed to familiarize you with ipfil- +ter's syntax, and firewall theory in general. The features +discussed here are features you'll find in any good firewall +package. This section will give you a good foundation to +make reading and understanding the advanced section very +easy. It must be emphasized that this section alone is not +enough to build a good firewall, and that the advanced sec- +tion really is required reading for anybody who wants to +build an effective security system. + + + + + + + + + + + + + -3- + + +2.1. Config File Dynamics, Order and Precedence + + IPF (IP Filter) has a config file (as opposed to say, +running some command again and again for each new rule). +The config file drips with Unix: There's one rule per line, +the "#" mark denotes a comment, and you can have a rule and +a comment on the same line. Extraneous whitespace is +allowed, and is encouraged to keep the rules readable. + + +2.2. Basic Rule Processing + + The rules are processed from top to bottom, each one +appended after another. This quite simply means that if the +entirety of your config file is: + + block in all + pass in all + +The computer sees it as: + + block in all + pass in all + +Which is to say that when a packet comes in, the first thing +IPF applies is: + + block in all + +Should IPF deem it necessary to move on to the next rule, it +would then apply the second rule: + + pass in all + + At this point, you might want to ask yourself "would +IPF move on to the second rule?" If you're familiar with +ipfwadm or ipfw, you probably won't ask yourself this. +Shortly after, you will become bewildered at the weird way +packets are always getting denied or passed when they +shouldn't. Many packet filters stop comparing packets to +rulesets the moment the first match is made; IPF is not one +of them. + + Unlike the other packet filters, IPF keeps a flag on +whether or not it's going to pass the packet. Unless you +interrupt the flow, IPF will go through the entire ruleset, +making its decision on whether or not to pass or drop the +packet based on the last matching rule. The scene: IP Fil- +ter's on duty. It's been been scheduled a slice of CPU +time. It has a checkpoint clipboard that reads: + + block in all + pass in all + + + + + + + + + + + -4- + + +A packet comes in the interface and it's time to go to work. +It takes a look at the packet, it takes a look at the first +rule: + + block in all + +"So far I think I will block this packet" says IPF. It +takes a look at the second rule: + + pass in all + +"So far I think I will pass this packet" says IPF. It takes +a look at a third rule. There is no third rule, so it goes +with what its last motivation was, to pass the packet +onward. + +It's a good time to point out that even if the ruleset had +been + + block in all + block in all + block in all + block in all + pass in all + +that the packet would still have gone through. There is no +cumulative effect. The last matching rule always takes +precedence. + +2.3. Controlling Rule Processing + + If you have experience with other packet filters, you +may find this layout to be confusing, and you may be specu- +lating that there are problems with portability with other +filters and speed of rule matching. Imagine if you had 100 +rules and most of the applicable ones were the first 10. +There would be a terrible overhead for every packet coming +in to go through 100 rules every time. Fortunately, there +is a simple keyword you can add to any rule that makes it +take action at that match. That keyword is quick. + +Here's a modified copy of the original ruleset using the +quick keyword: + + block in quick all + pass in all + +In this case, IPF looks at the first rule: + + block in quick all + +The packet matches and the search is over. The packet is +expunged without a peep. There are no notices, no logs, no +memorial service. Cake will not be served. So what about + + + + + + + + + + -5- + + +the next rule? + + pass in all + + This rule is never encountered. It could just as eas- +ily not be in the config file at all. The sweeping match of +all and the terminal keyword quick from the previous rule +make certain that no rules are followed afterward. + + Having half a config file laid to waste is rarely a +desirable state. On the other hand, IPF is here to block +packets and as configured, it's doing a very good job. +Nonetheless, IPF is also here to let some packets through, +so a change to the ruleset to make this possible is called +for. + +2.4. Basic filtering by IP address + + IPF will match packets on many criteria. The one that +we most commonly think of is the IP address. There are some +blocks of address space from which we should never get traf- +fic. One such block is from the unroutable networks, +192.168.0.0/16 (/16 is the CIDR notation for a netmask. You +may be more familiar with the dotted decimal format, +255.255.0.0. IPF accepts both). If you wanted to block +192.168.0.0/16, this is one way to do it: + + block in quick from 192.168.0.0/16 to any + pass in all + +Now we have a less stringent ruleset that actually does +something for us. Let's imagine a packet comes in from +1.2.3.4. The first rule is applied: + + block in quick from 192.168.0.0/16 to any + +The packet is from 1.2.3.4, not 192.168.*.*, so there is no +match. The second rule is applied: + + pass in all + +The packet from 1.2.3.4 is definitely a part of all, so the +packet is sent to whatever it's destination happened to be. + + On the other hand, suppose we have a packet that comes +in from 192.168.1.2. The first rule is applied: + + block in quick from 192.168.0.0/16 to any + +There's a match, the packet is dropped, and that's the end. +Again, it doesn't move to the second rule because the first +rule matches and contains the quick keyword. + + + + + + + + + + + + -6- + + + At this point you can build a fairly extensive set of +definitive addresses which are passed or blocked. Since +we've already started blocking private address space from +entering our firewall, let's take care of the rest of it: + + block in quick from 192.168.0.0/16 to any + block in quick from 172.16.0.0/12 to any + block in quick from 10.0.0.0/8 to any + pass in all + +The first three address blocks are some of the private IP +space. + +2.5. Controlling Your Interfaces + + It seems very frequent that companies have internal +networks before they want a link to the outside world. In +fact, it's probably reasonable to say that's the main reason +people consider firewalls in the first place. The machine +that bridges the outside world to the inside world and vice +versa is the router. What separates the router from any +other machine is simple: It has more than one interface. + + Every packet you receive comes from a network inter- +face; every packet you transmit goes out a network inter- +face. Say your machine has 3 interfaces, lo0 (loopback), +xl0 (3com ethernet), and tun0 (FreeBSD's generic tunnel +interface that PPP uses), but you don't want packets coming +in on the tun0 interface? + + block in quick on tun0 all + pass in all + +In this case, the on keyword means that the data is coming +in on the named interface. If a packet comes in on tun0, +the first rule will block it. If a packet comes in on lo0 +or in on xl0, the first rule will not match, the second rule +will, the packet will be passed. + +2.6. Using IP Address and Interface Together + + It's an odd state of affairs when one decides it best +to have the tun0 interface up, but not allow any data to be +received from it. The more criteria the firewall matches +against, the tighter (or looser) the firewall can become. +Maybe you want data from tun0, but not from 192.168.0.0/16? +This is the start of a powerful firewall. + + block in quick on tun0 from 192.168.0.0/16 to any +----------- + See rfc1918 at +<http://www.faqs.org/rfcs/rfc1918.html> and +<http://www.ietf.org/internet-drafts/draft-man- +ning-dsua-06.txt> + + + + + + + + + + -7- + + + pass in all + +Compare this to our previous rule: + + block in quick from 192.168.0.0/16 to any + pass in all + +The old way, all traffic from 192.168.0.0/16, regardless of +interface, was completely blocked. The new way, using on +tun0 means that it's only blocked if it comes in on the tun0 +interface. If a packet arrived on the xl0 interface from +192.168.0.0/16, it would be passed. + + At this point you can build a fairly extensive set of +definitive addresses which are passed or blocked. Since +we've already started blocking private address space from +entering tun0, let's take care of the rest of it: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + pass in all + +You've already seen the first three blocks, but not the +rest. The fourth is a largely wasted class-A network used +for loopback. Much software communicates with itself on +127.0.0.1 so blocking it from an external source is a good +idea. The fifth, 0.0.0.0/8, should never be seen on the +internet. Most IP stacks treat "0.0.0.0/32" as the default +gateway, and the rest of the 0.*.*.* network gets handled +strangely by various systems as a byproduct of how routing +decisions are made. You should treat 0.0.0.0/8 just like +127.0.0.0/8. 169.254.0.0/16 has been assigned by the IANA +for use in auto-configuration when systems have not yet been +able to obtain an IP address via DHCP or the like. Most +notably, Microsoft Windows will use addresses in this range +if they are set to DHCP and cannot find a DHCP server. +192.0.2.0/24 has also been reserved for use as an example IP +netblock for documentation authors. We specifically do not +use this range as it would cause confusion when we tell you +to block it, and thus all our examples come from +20.20.20.0/24. 204.152.64.0/23 is an odd netblock reserved +by Sun Microsystems for private cluster interconnects, and +blocking this is up to your own judgement. Lastly, +224.0.0.0/3 wipes out the "Class D and E" networks which is +used mostly for multicast traffic, although further defini- +tion of "Class E" space can be found in RFC 1166. + + + + + + + + + + + -8- + + + There's a very important principle in packet filtering +which has only been alluded to with the private network +blocking and that is this: When you know there's certain +types of data that only comes from certain places, you setup +the system to only allow that kind of data from those +places. In the case of the unroutable addresses, you know +that nothing from 10.0.0.0/8 should be arriving on tun0 +because you have no way to reply to it. It's an illegiti- +mate packet. The same goes for the other unroutables as +well as 127.0.0.0/8. + + Many pieces of software do all their authentication +based upon the packet's originating IP address. When you +have an internal network, say 20.20.20.0/24, you know that +the only traffic for that internal network is going to come +off the local ethernet. Should a packet from 20.20.20.0/24 +arrive over a PPP dialup, it's perfectly reasonable to drop +it on the floor, or put it in a dark room for interrogation. +It should by no means be allowed to get to its final desti- +nation. You can accomplish this particularly easily with +what you already know of IPF. The new ruleset would be: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in quick on tun0 from 20.20.20.0/24 to any + pass in all + +2.7. Bi-Directional Filtering; The "out" Keyword + + Up until now, we've been passing or blocking inbound +traffic. To clarify, inbound traffic is all traffic that +enters the firewall on any interface. Conversely, outbound +traffic is all traffic that leaves on any interface (whether +locally generated or simply passing through). This means +that all packets coming in are not only filtered as they +enter the firewall, they're also filtered as they exit. +Thusfar there's been an implied pass out all that may or may +not be desirable. Just as you may pass and block incoming +traffic, you may do the same with outgoing traffic. + + Now that we know there's a way to filter outbound pack- +ets just like inbound, it's up to us to find a conceivable +use for such a thing. One possible use of this idea is to +keep spoofed packets from exiting your own network. Instead +of passing any traffic out the router, you could instead +limit permitted traffic to packets originating at + + + + + + + + + + + -9- + + +20.20.20.0/24. You might do it like this: + + pass out quick on tun0 from 20.20.20.0/24 to any + block out quick on tun0 from any to any + +If a packet comes from 20.20.20.1/32, it gets sent out by +the first rule. If a packet comes from 1.2.3.4/32 it gets +blocked by the second. + + You can also make similar rules for the unroutable +addresses. If some machine tries to route a packet through +IPF with a destination in 192.168.0.0/16, why not drop it? +The worst that can happen is that you'll spare yourself some +bandwidth: + + block out quick on tun0 from any to 192.168.0.0/16 + block out quick on tun0 from any to 172.16.0.0/12 + block out quick on tun0 from any to 10.0.0.0/8 + block out quick on tun0 from any to 0.0.0.0/8 + block out quick on tun0 from any to 127.0.0.0/8 + block out quick on tun0 from any to 169.254.0.0/16 + block out quick on tun0 from any to 192.0.2.0/24 + block out quick on tun0 from any to 204.152.64.0/23 + block out quick on tun0 from any to 224.0.0.0/3 + block out quick on tun0 from !20.20.20.0/24 to any + +In the narrowest viewpoint, this doesn't enhance your secu- +rity. It enhances everybody else's security, and that's a +nice thing to do. As another viewpoint, one might suppose +that because nobody can send spoofed packets from your site, +that your site has less value as a relay for crackers, and +as such is less of a target. + + You'll likely find a number of uses for blocking out- +bound packets. One thing to always keep in mind is that in +and out directions are in reference to your firewall, never +any other machine. + +2.8. Logging What Happens; The "log" Keyword + + Up to this point, all blocked and passed packets have +been silently blocked and silently passed. Usually you want +to know if you're being attacked rather than wonder if that +firewall is really buying you any added benefits. While I +wouldn't want to log every passed packet, and in some cases +every blocked packet, I would want to know about the blocked +packets from 20.20.20.0/24. To do this, we add the log key- +word: + + block in quick on tun0 from 192.168.0.0/16 to any +----------- + This can, of course, be changed by using -DIPFIL- +TER_DEFAULT_BLOCK when compiling ipfilter on your +system. + + + + + + + + + + -10- + + + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + pass in all + +So far, our firewall is pretty good at blocking packets com- +ing to it from suspect places, but there's still more to be +done. For one thing, we're accepting packets destined any- +where. One thing we ought to do is make sure packets to +20.20.20.0/32 and 20.20.20.255/32 get dropped on the floor. +To do otherwise opens the internal network for a smurf +attack. These two lines would prevent our hypothetical net- +work from being used as a smurf relay: + + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + +This brings our total ruleset to look something like this: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +2.9. Complete Bi-Directional Filtering By Interface + + So far we have only presented fragments of a complete +ruleset. When you're actually creating your ruleset, you +should setup rules for every direction and every interface. +The default state of ipfilter is to pass packets. It is as +though there were an invisible rule at the beginning which +states pass in all and pass out all. Rather than rely on +some default behaviour, make everything as specific as pos- +sible, interface by interface, until every base is covered. + + First we'll start with the lo0 interface, which wants +to run wild and free. Since these are programs talking to +others on the local system, go ahead and keep it unre- +stricted: + + + + + + + + + + -11- + + + pass out quick on lo0 + pass in quick on lo0 + +Next, there's the xl0 interface. Later on we'll begin plac- +ing restrictions on the xl0 interface, but to start with, +we'll act as though everything on our local network is +trustworthy and give it much the same treatment as lo0: + + pass out quick on xl0 + pass in quick on xl0 + +Finally, there's the tun0 interface, which we've been half- +filtering with up until now: + + block out quick on tun0 from any to 192.168.0.0/16 + block out quick on tun0 from any to 172.16.0.0/12 + block out quick on tun0 from any to 127.0.0.0/8 + block out quick on tun0 from any to 10.0.0.0/8 + block out quick on tun0 from any to 0.0.0.0/8 + block out quick on tun0 from any to 169.254.0.0/16 + block out quick on tun0 from any to 192.0.2.0/24 + block out quick on tun0 from any to 204.152.64.0/23 + block out quick on tun0 from any to 224.0.0.0/3 + pass out quick on tun0 from 20.20.20.0/24 to any + block out quick on tun0 from any to any + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +This is a pretty significant amount of filtering already, +protecting 20.20.20.0/24 from being spoofed or being used +for spoofing. Future examples will continue to show one- +sideness, but keep in mind that it's for brevity's sake, and +when setting up your own ruleset, adding rules for every +direction and every interface is necessary. + + +2.10. Controlling Specific Protocols; The "proto" Keyword + + Denial of Service attacks are as rampant as buffer +overflow exploits. Many denial of service attacks rely on +glitches in the OS's TCP/IP stack. Frequently, this has +come in the form of ICMP packets. Why not block them + + + + + + + + + + -12- + + +entirely? + + block in log quick on tun0 proto icmp from any to any + +Now any ICMP traffic coming in from tun0 will be logged and +discarded. + +2.11. Filtering ICMP with the "icmp-type" Keyword; Merging +Rulesets + + Of course, dropping all ICMP isn't really an ideal sit- +uation. Why not drop all ICMP? Well, because it's useful +to have partially enabled. So maybe you want to keep some +types of ICMP traffic and drop other kinds. If you want +ping and traceroute to work, you need to let in ICMP types 0 +and 11. Strictly speaking, this might not be a good idea, +but if you need to weigh security against convenience, IPF +lets you do it. + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + +Remember that ruleset order is important. Since we're doing +everything quick we must have our passes before our blocks, +so we really want the last three rules in this order: + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + +Adding these 3 rules to the anti-spoofing rules is a bit +tricky. One error might be to put the new ICMP rules at the +beginning: + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +The problem with this is that an ICMP type 0 packet from +192.168.0.0/16 will get passed by the first rule, and never +blocked by the fourth rule. Also, since we quickly pass an + + + + + + + + + + -13- + + +ICMP ECHO_REPLY (type 0) to 20.20.20.0/24, we've just opened +ourselves back up to a nasty smurf attack and nullified +those last two block rules. Oops. To avoid this, we place +the ICMP rules after the anti-spoofing rules: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + pass in all + +Because we block spoofed traffic before the ICMP rules are +processed, a spoofed packet never makes it to the ICMP rule- +set. It's very important to keep such situations in mind +when merging rules. + +2.12. TCP and UDP Ports; The "port" Keyword + + Now that we've started blocking packets based on proto- +col, we can start blocking packets based on specific aspects +of each protocol. The most frequently used of these aspects +is the port number. Services such as rsh, rlogin, and tel- +net are all very convenient to have, but also hideously +insecure against network sniffing and spoofing. One great +compromise is to only allow the services to run internally, +then block them externally. This is easy to do because +rlogin, rsh, and telnet use specific TCP ports (513, 514, +and 23 respectively). As such, creating rules to block them +is easy: + + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + +Make sure all 3 are before the pass in all and they'll be +closed off from the outside (leaving out spoofing for +brevity's sake): + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514 + + + + + + + + + + -14- + + + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + pass in all + +You might also want to block 514/udp (syslog), 111/tcp & +111/udp (portmap), 515/tcp (lpd), 2049/tcp and 2049/udp +(NFS), 6000/tcp (X11) and so on and so forth. You can get a +complete listing of the ports being listened to by using +netstat -a (or lsof -i, if you have it installed). + + Blocking UDP instead of TCP only requires replacing +proto tcp with proto udp. The rule for syslog would be: + + block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 514 + +IPF also has a shorthand way to write rules that apply to +both proto tcp and proto udp at the same time, such as +portmap or NFS. The rule for portmap would be: + + block in log quick on tun0 proto tcp/udp from any to 20.20.20.0/24 port = 111 + + + + +3. Advanced Firewalling Introduction + + This section is designed as an immediate followup to +the basic section. Contained below are both concepts for +advanced firewall design, and advanced features contained +only within ipfilter. Once you are comfortable with this +section, you should be able to build a very strong firewall. + +3.1. Rampant Paranoia; or The Default-Deny Stance + + There's a big problem with blocking services by the +port: sometimes they move. RPC based programs are terrible +about this, lockd, statd, even nfsd listens places other +than 2049. It's awfully hard to predict, and even worse to +automate adjusting all the time. What if you miss a ser- +vice? Instead of dealing with all that hassle, let's start +over with a clean slate. The current ruleset looks like +this: + + + + + Yes, we really are starting over. The first rule we're +going to use is this: + + block in all + +No network traffic gets through. None. Not a peep. You're +rather secure with this setup. Not terribly useful, but +quite secure. The great thing is that it doesn't take much +more to make your box rather secure, yet useful too. Let's + + + + + + + + + + -15- + + +say the machine this is running on is a web server, nothing +more, nothing less. It doesn't even do DNS lookups. It +just wants to take connections on 80/tcp and that's it. We +can do that. We can do that with a second rule, and you +already know how: + + block in on tun0 all + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 + +This machine will pass in port 80 traffic for 20.20.20.1, +and deny everything else. For basic firewalling, this is +all one needs. + +3.2. Implicit Allow; The "keep state" Rule + + The job of your firewall is to prevent unwanted traffic +getting to point B from point A. We have general rules +which say "as long as this packet is to port 23, it's okay." +We have general rules which say "as long as this packet has +its FIN flag set, it's okay." Our firewalls don't know the +beginning, middle, or end of any TCP/UDP/ICMP session. They +merely have vague rules that are applied to all packets. +We're left to hope that the packet with its FIN flag set +isn't really a FIN scan, mapping our services. We hope that +the packet to port 23 isn't an attempted hijack of our tel- +net session. What if there was a way to identify and autho- +rize individual TCP/UDP/ICMP sessions and distinguish them +from port scanners and DoS attacks? There is a way, it's +called keeping state. + + We want convenience and security in one. Lots of peo- +ple do, that's why Ciscos have an "established" clause that +lets established tcp sessions go through. Ipfw has estab- +lished. Ipfwadm has setup/established. They all have this +feature, but the name is very misleading. When we first saw +it, we thought it meant our packet filter was keeping track +of what was going on, that it knew if a connection was +really established or not. The fact is, they're all taking +the packet's word for it from a part of the packet anybody +can lie about. They read the TCP packet's flags section and +there's the reason UDP/ICMP don't work with it, they have no +such thing. Anybody who can create a packet with bogus +flags can get by a firewall with this setup. + + Where does IPF come in to play here, you ask? Well, +unlike the other firewalls, IPF really can keep track of +whether or not a connection is established. And it'll do it +with TCP, UDP and ICMP, not just TCP. Ipf calls it keeping +state. The keyword for the ruleset is keep state. + + Up until now, we've told you that packets come in, then +the ruleset gets checked; packets go out, then the ruleset +gets checked. Actually, what happens is packets come in, +the state table gets checked, then *maybe* the inbound + + + + + + + + + + -16- + + +ruleset gets checked; packets go out, the state table gets +checked, then *maybe* the outbound ruleset gets checked. +The state table is a list of TCP/UDP/ICMP sessions that are +unquestionadely passed through the firewall, circumventing +the entire ruleset. Sound like a serious security hole? +Hang on, it's the best thing that ever happened to your +firewall. + + All TCP/IP sessions have a start, a middle, and an end +(even though they're sometimes all in the same packet). You +can't have an end without a middle and you can't have a mid- +dle without a start. This means that all you really need to +filter on is the beginning of a TCP/UDP/ICMP session. If +the beginning of the session is allowed by your firewall +rules, you really want the middle and end to be allowed too +(lest your IP stack should overflow and your machines become +useless). Keeping state allows you to ignore the middle and +end and simply focus on blocking/passing new sessions. If +the new session is passed, all its subsequent packets will +be allowed through. If it's blocked, none of its subsequent +packets will be allowed through. Here's an example for run- +ning an ssh server (and nothing but an ssh server): + + block out quick on tun0 all + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 22 keep state + +The first thing you might notice is that there's no "pass +out" provision. In fact, there's only an all-inclusive +"block out" rule. Despite this, the ruleset is complete. +This is because by keeping state, the entire ruleset is cir- +cumvented. Once the first SYN packet hits the ssh server, +state is created and the remainder of the ssh session is +allowed to take place without interference from the fire- +wall. Here's another example: + + block in quick on tun0 all + pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state + +In this case, the server is running no services. Infact, +it's not a server, it's a client. And this client doesn't +want unauthorized packets entering its IP stack at all. +However, the client wants full access to the internet and +the reply packets that such privilege entails. This simple +ruleset creates state entries for every new outgoing TCP +session. Again, since a state entry is created, these new +TCP sessions are free to talk back and forth as they please +without the hindrance or inspection of the firewall rule- +set. We mentioned that this also works for UDP and ICMP: + + block in quick on tun0 all + pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto udp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state + + + + + + + + + + + -17- + + +Yes Virginia, we can ping. Now we're keeping state on TCP, +UDP, ICMP. Now we can make outgoing connections as though +there's no firewall at all, yet would-be attackers can't get +back in. This is very handy because there's no need to +track down what ports we're listening to, only the ports we +want people to be able to get to. + + State is pretty handy, but it's also a bit tricky. You +can shoot yourself in the foot in strange and mysterious +ways. Consider the following ruleset: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +At first glance, this seems to be a good setup. We allow +incoming sessions to port 23, and outgoing sessions any- +where. Naturally packets going to port 23 will have reply +packets, but the ruleset is setup in such a way that the +pass out rule will generate a state entry and everything +will work perfectly. At least, you'd think so. + + The unfortunate truth is that after 60 seconds of idle +time the state entry will be closed (as opposed to the nor- +mal 5 days). This is because the state tracker never saw +the original SYN packet destined to port 23, it only saw the +SYN ACK. IPF is very good about following TCP sessions from +start to finish, but it's not very good about coming into +the middle of a connection, so rewrite the rule to look like +this: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +The additional of this rule will enter the very first packet +into the state table and everything will work as expected. +Once the 3-way handshake has been witness by the state +engine, it is marked in 4/4 mode, which means it's setup for +long-term data exchange until such time as the connection is +torn down (wherein the mode changes again. You can see the +current modes of your state table with ipfstat -s. + +3.3. Stateful UDP + + UDP is stateless so naturally it's a bit harder to do a +reliable job of keeping state on it. Nonetheless, ipf does +a pretty good job. When machine A sends a UDP packet to +machine B with source port X and destination port Y, ipf +will allow a reply from machine B to machine A with source +port Y and destination port X. This is a short term state +entry, a mere 60 seconds. + + + + + + + + + + -18- + + + Here's an example of what happens if we use nslookup to +get the IP address of www.3com.com: + + $ nslookup www.3com.com + + A DNS packet is generated: + + 17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+ + +The packet is from 20.20.20.1, port 2111, destined for +198.41.0.5, port 53. A 60 second state entry is created. +If a packet comes back from 198.41.0.5 port 53 destined for +20.20.20.1 port 2111 within that period of time, the reply +packet will be let through. As you can see, milliseconds +later: + + 17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: www.3com.com + +The reply packet matches the state criteria and is let +through. At that same moment that packet is let through, +the state gateway is closed and no new incoming packets will +be allowed in, even if they claim to be from the same place. + +3.4. Stateful ICMP + + IPFilter handles ICMP states in the manner that one +would expect from understanding how ICMP is used with TCP +and UDP, and with your understanding of how keep state +works. There are two general types of ICMP messages; +requests and replies. When you write a rule such as: + + pass out on tun0 proto icmp from any to any icmp-type 8 keep state + +to allow outbound echo requests (a typical ping), the resul- +tant icmp-type 0 packet that comes back will be allowed in. +This state entry has a default timeout of an incomplete 0/0 +state of 60 seconds. Thus, if you are keeping state on any +outbound icmp message that will elicit an icmp message in +reply, you need a proto icmp [...] keep state rule. + + However, the majority of ICMP messages are status mes- +sages generated by some failure in UDP (and sometimes TCP), +and in 3.4.x and greater IPFilters, any ICMP error status +message (say icmp-type 3 code 3 port unreachable, or icmp- +type 11 time exceeded) that matches an active state table +entry that could have generated that message, the ICMP +packet is let in. For example, in older IPFilters, if you +wanted traceroute to work, you needed to use: + + pass out on tun0 proto udp from any to any port 33434><33690 keep state + pass in on tun0 proto icmp from any to any icmp-type timex + +whereas now you can do the right thing and just keep state +on udp with: + + + + + + + + + + -19- + + + pass out on tun0 proto udp from any to any port 33434><33690 keep state + +To provide some protection against a third-party sneaking +ICMP messages through your firewall when an active connec- +tion is known to be in your state table, the incoming ICMP +packet is checked not only for matching source and destina- +tion addresses (and ports, when applicable) but a tiny part +of the payload of the packet that the ICMP message is claim- +ing it was generated by. + +3.5. FIN Scan Detection; "flags" Keyword, "keep frags" Key- +word + +Let's go back to the 4 rule set from the previous section: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +This is almost, but not quite, satisfactory. The problem is +that it's not just SYN packets that're allowed to go to port +23, any old packet can get through. We can change this by +using the flags option: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state + pass out quick on tun0 proto tcp from any to any flags S keep state + block in quick all + block out quick all + +Now only TCP packets, destined for 20.20.20.1, at port 23, +with a lone SYN flag will be allowed in and entered into the +state table. A lone SYN flag is only present as the very +first packet in a TCP session (called the TCP handshake) and +that's really what we wanted all along. There's at least +two advantages to this: No arbitrary packets can come in +and make a mess of your state table. Also, FIN and XMAS +scans will fail since they set flags other than the SYN +flag. Now all incoming packets must either be handshakes or +have state already. If anything else comes in, it's proba- +bly a port scan or a forged packet. There's one exception +to that, which is when a packet comes in that's fragmented +from its journey. IPF has provisions for this as well, the +----------- + Some examples use flags S/SA instead of flags S. +flags S actually equates to flags S/AUPRFS and +matches against only the SYN packet out of all six +possible flags, while flags S/SA will allow pack- +ets that may or may not have the URG, PSH, FIN, or +RST flags set. Some protocols demand the URG or +PSH flags, and S/SAFR would be a better choice for +these, however we feel that it is less secure to +blindly use S/SA when it isn't required. But it's +your firewall. + + + + + + + + + + -20- + + +keep frags keyword. With it, IPF will notice and keep track +of packets that are fragmented, allowing the expected frag- +ments to go through. Let's rewrite the 3 rules to log +forgeries and allow fragments: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags + pass out quick on tun0 proto tcp from any to any keep state flags S keep frags + block in log quick all + block out log quick all + +This works because every packet that should be allowed +through makes it into the state table before the blocking +rules are reached. The only scan this won't detect is a SYN +scan itself. If you're truly worried about that, you might +even want to log all initial SYN packets. + +3.6. Responding To a Blocked Packet + + So far, all of our blocked packets have been dumped on +the floor, logged or not, we've never sent anything back to +the originating host. Sometimes this isn't the most desir- +able of responses because in doing so, we actually tell the +attacker that a packet filter is present. It seems a far +better thing to misguide the attacker into believing that, +while there's no packet filter running, there's likewise no +services to break into. This is where fancier blocking +comes into play. + + When a service isn't running on a Unix system, it nor- +mally lets the remote host know with some sort of return +packet. In TCP, this is done with an RST (Reset) packet. +When blocking a TCP packet, IPF can actually return an RST +to the origin by using the return-rst keyword. + +Where once we did: + + block in log on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + pass in all + +We might now do: + + block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23 + block in log quick on tun0 + pass in all + +We need two block statements since return-rst only works +with TCP, and we still want to block protocols such as UDP, +ICMP, and others. Now that this is done, the remote side +will get "connection refused" instead of "connection timed +out". + + It's also possible to send an error message when some- +body sends a packet to a UDP port on your system. Whereas +once you might have used: + + + + + + + + + + -21- + + + block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +You could instead use the return-icmp keyword to send a +reply: + + block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +According to TCP/IP Illustrated, port-unreachable is the +correct ICMP type to return when no service is listening on +the port in question. You can use any ICMP type you like, +but port-unreachable is probably your best bet. It's also +the default ICMP type for return-icmp. + + However, when using return-icmp, you'll notice that +it's not very stealthy, and it returns the ICMP packet with +the IP address of the firewall, not the original destination +of the packet. This was fixed in ipfilter 3.3, and a new +keyword; return-icmp-as-dest, has been added. The new for- +mat is: + + block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +3.7. Fancy Logging Techniques + + It is important to note that the presence of the log +keyword only ensures that the packet will be available to +the ipfilter logging device; /dev/ipl. In order to actu- +ally see this log information, one must be running the ipmon +utility (or some other utility that reads from /dev/ipl). +The typical usage of log is coupled with ipmon -s to log the +information to syslog. As of ipfilter 3.3, one can now even +control the logging behavior of syslog by using log level +keywords, as in rules such as this: + + block in log level auth.info quick on tun0 from 20.20.20.0/24 to any + block in log level auth.alert quick on tun0 proto tcp from any to 20.20.20.0/24 port = 21 + +In addition to this, you can tailor what information is +being logged. For example, you may not be interested that +someone attempted to probe your telnet port 500 times, but +you are interested that they probed you once. You can use +the log first keyword to only log the first example of a +packet. Of course, the notion of "first-ness" only applies +to packets in a specific session, and for the typical +blocked packet, you will be hard pressed to encounter situa- +tions where this does what you expect. However, if used in +conjunction with pass and keep state, this can be a valuable +keyword for keeping tabs on traffic. + + Another useful thing you can do with the logs is to +keep track of interesting pieces of the packet in addition +to the header information normally being logged. Ipfilter +will give you the first 128 bytes of the packet if you use +the log body keyword. You should limit the use of body + + + + + + + + + + -22- + + +logging, as it makes your logs very verbose, but for certain +applications, it is often handy to be able to go back and +take a look at the packet, or to send this data to another +application that can examine it further. + +3.8. Putting It All Together + + So now we have a pretty tight firewall, but it can +still be tighter. Some of the original ruleset we wiped +clean is actually very useful. I'd suggest bringing back +all the anti-spoofing stuff. This leaves us with: + + block in on tun0 + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass out quick on tun0 proto tcp/udp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 flags S keep state + +3.9. Improving Performance With Rule Groups + + Let's extend our use of our firewall by creating a much +more complicated, and we hope more applicable to the real +world, example configuration For this example, we're going +to change the interface names, and network numbers. Let's +assume that we have three interfaces in our firewall with +interfaces xl0, xl1, and xl2. + +xl0 is connected to our external network 20.20.20.0/26 +xl1 is connected to our "DMZ" network 20.20.20.64/26 +xl2 is connected to our protected network 20.20.20.128/25 + +We'll define the entire ruleset in one swoop, since we fig- +ure that you can read these rules by now: + + block in quick on xl0 from 192.168.0.0/16 to any + block in quick on xl0 from 172.16.0.0/12 to any + block in quick on xl0 from 10.0.0.0/8 to any + block in quick on xl0 from 127.0.0.0/8 to any + block in quick on xl0 from 0.0.0.0/8 to any + block in quick on xl0 from 169.254.0.0/16 to any + block in quick on xl0 from 192.0.2.0/24 to any + block in quick on xl0 from 204.152.64.0/23 to any + block in quick on xl0 from 224.0.0.0/3 to any + + + + + + + + + + -23- + + + block in log quick on xl0 from 20.20.20.0/24 to any + block in log quick on xl0 from any to 20.20.20.0/32 + block in log quick on xl0 from any to 20.20.20.63/32 + block in log quick on xl0 from any to 20.20.20.64/32 + block in log quick on xl0 from any to 20.20.20.127/32 + block in log quick on xl0 from any to 20.20.20.128/32 + block in log quick on xl0 from any to 20.20.20.255/32 + pass out on xl0 all + + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state + pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state + block out on xl1 all + pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state + + block out on xl2 all + pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state + +From this arbitarary example, we can already see that our +ruleset is becoming unwieldy. To make matters worse, as we +add more specific rules to our DMZ network, we add addi- +tional tests that must be parsed for every packet, which +affects the performance of the xl0 <-> xl2 connections. If +you set up a firewall with a ruleset like this, and you have +lots of bandwidth and a moderate amount of cpu, everyone +that has a workstation on the xl2 network is going to come +looking for your head to place on a platter. So, to keep +your head <-> torso network intact, you can speed things +along by creating rule groups. Rule groups allow you to +write your ruleset in a tree fashion, instead of as a linear +list, so that if your packet has nothing to do with the set +of tests (say, all those xl1 rules) those rules will never +be consulted. It's somewhat like having multiple firewalls +all on the same machine. + +Here's a simple example to get us started: + + block out quick on xl1 all head 10 + pass out quick proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10 + block out on xl2 all + +In this simplistic example, we can see a small hint of the +power of the rule group. If the packet is not destined for +xl1, the head of rule group 10 will not match, and we will +go on with our tests. If the packet does match for xl1, the +quick keyword will short-circuit all further processing at +the root level (rule group 0), and focus the testing on +rules which belong to group 10; namely, the SYN check for +80/tcp. In this way, we can re-write the above rules so +that we can maximize performance of our firewall. + + + + + + + + + + -24- + + + block in quick on xl0 all head 1 + block in quick on xl0 from 192.168.0.0/16 to any group 1 + block in quick on xl0 from 172.16.0.0/12 to any group 1 + block in quick on xl0 from 10.0.0.0/8 to any group 1 + block in quick on xl0 from 127.0.0.0/8 to any group 1 + block in quick on xl0 from 0.0.0.0/8 to any group 1 + block in quick on xl0 from 169.254.0.0/16 to any group 1 + block in quick on xl0 from 192.0.2.0/24 to any group 1 + block in quick on xl0 from 204.152.64.0/23 to any group 1 + block in quick on xl0 from 224.0.0.0/3 to any group 1 + block in log quick on xl0 from 20.20.20.0/24 to any group 1 + block in log quick on xl0 from any to 20.20.20.0/32 group 1 + block in log quick on xl0 from any to 20.20.20.63/32 group 1 + block in log quick on xl0 from any to 20.20.20.64/32 group 1 + block in log quick on xl0 from any to 20.20.20.127/32 group 1 + block in log quick on xl0 from any to 20.20.20.128/32 group 1 + block in log quick on xl0 from any to 20.20.20.255/32 group 1 + pass in on xl0 all group 1 + + pass out on xl0 all + + block out quick on xl1 all head 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state group 10 + pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state group 10 + + pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state + + block out on xl2 all + + pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state + +Now you can see the rule groups in action. For a host on +the xl2 network, we can completely bypass all the checks in +group 10 when we're not communicating with hosts on that +network. + + Depending on your situation, it may be prudent to group +your rules by protocol, or various machines, or netblocks, +or whatever makes it flow smoothly. + +3.10. "Fastroute"; The Keyword of Stealthiness + + Even though we're forwarding some packets, and blocking +other packets, we're typically behaving like a well behaved +router should by decrementing the TTL on the packet and +acknowledging to the entire world that yes, there is a hop +here. But we can hide our presence from inquisitive appli- +cations like unix traceroute which uses UDP packets with +various TTL values to map the hops between two sites. If we + + + + + + + + + + -25- + + +want incoming traceroutes to work, but we do not want to +announce the presence of our firewall as a hop, we can do so +with a rule like this: + + block in quick on xl0 fastroute proto udp from any to any port 33434 >< 33465 + +The presence of the fastroute keyword will signal ipfilter +to not pass the packet into the Unix IP stack for routing +which results in a TTL decrement. The packet will be placed +gently on the output interface by ipfilter itself and no +such decrement will happen. Ipfilter will of course use the +system's routing table to figure out what the appropriate +output interface really is, but it will take care of the +actual task of routing itself. + + There's a reason we used block quick in our example, +too. If we had used pass, and if we had IP Forwarding +enabled in our kernel, we would end up having two paths for +a packet to come out of, and we would probably panic our +kernel. + + It should be noted, however, that most Unix kernels +(and certainly the ones underlying the systems that ipfilter +usually runs on) have far more efficient routing code than +what exists in ipfilter, and this keyword should not be +thought of as a way to improve the operating speed of your +firewall, and should only be used in places where stealth is +an issue. + + + + +4. NAT and Proxies + + Outside of the corporate environment, one of the +biggest enticements of firewall technology to the end user +is the ability to connect several computers through a common +external interface, often without the approval, knowledge, +or even consent of their service provider. To those famil- +iar with Linux, this concept is called IP Masquerading, but +to the rest of the world it is known by the more obscure +name of Network Address Translation, or NAT for short. + +4.1. Mapping Many Addresses Into One Address + + The basic use of NAT accomplishes much the same thing +that Linux's IP Masquerading function does, and it does it +----------- + To be pedantic, what IPFilter provides is really +called NPAT, for Network and Port Address Transla- +tion, which means we can change any of the source +and destination IP Addresses and their source and +destination ports. True NAT only allows one to +change the addresses. + + + + + + + + + + -26- + + +with one simple rule: + + map tun0 192.168.1.0/24 -> 20.20.20.1/32 + +Very simple. Whenever a packet goes out the tun0 interface +with a source address matching the CIDR network mask of +192.168.1.0/24 this packet will be rewritten within the IP +stack such that its source address is 20.20.20.1, and it +will be sent on to its original destination. The system +also keeps a list of what translated connections are in +progress so that it can perform the reverse and remap the +response (which will be directed to 20.20.20.1) to the +internal host that really generated the packet. + + There is a drawback to the rule we have just written, +though. In a large number of cases, we do not happen to +know what the IP address of our outside link is (if we're +using tun0 or ppp0 and a typical ISP) so it makes setting up +our NAT tables a chore. Luckily, NAT is smart enough to +accept an address of 0/32 as a signal that it needs to go +look at what the address of that interface really is and we +can rewrite our rule as follows: + + map tun0 192.168.1.0/24 -> 0/32 + +Now we can load our ipnat rules with impunity and connect to +the outside world without having to edit anything. You do +have to run ipf -y to refresh the address if you get discon- +nected and redial or if your DHCP lease changes, though. + + Some of you may be wondering what happens to the source +port when the mapping happens. With our current rule, the +packet's source port is unchanged from the original source +port. There can be instances where we do not desire this +behavior; maybe we have another firewall further upstream we +have to pass through, or perhaps many hosts are trying to +use the same source port, causing a collision where the rule +doesn't match and the packet is passed untranslated. ipnat +helps us here with the portmap keyword: + + map tun0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:30000 + +Our rule now shoehorns all the translated connections (which +can be tcp, udp, or tcp/udp) into the port range of 20000 to +30000. + + + +----------- + This is a typical internal address space, since +it's non-routable on the Real Internet it is often +used for internal networks. You should still +block these packets coming in from the outside +world as discussed earlier. + + + + + + + + + + -27- + + +4.2. Mapping Many Addresses Into a Pool of Addresses + + Another use common use of NAT is to take a small stati- +cally allocated block of addresses and map many computers +into this smaller address space. This is easy to accom- +plish using what you already know about the map and portmap +keywords by writing a rule like so: + + map tun0 192.168.0.0/16 -> 20.20.20.0/24 portmap tcp/udp 20000:60000 + +Also, there may be instances where a remote application +requires that multiple connections all come from the same IP +address. We can help with these situations by telling NAT +to statically map sessions from a host into the pool of +addresses and work some magic to choose a port. This uses a +the keyword map-block as follows: + + map-block tun0 192.168.1.0/24 -> 20.20.20.0/24 + +4.3. One to One Mappings + + Occasionally it is desirable to have a system with one +IP address behind the firewall to appear to have a com- +pletely different IP address. One example of how this would +work would be a lab of computers which are then attached to +various networks that are to be put under some kind of test. +In this example, you would not want to have to reconfigure +the entire lab when you could place a NAT system in front +and change the addresses in one simple place. We can do +that with the bimap keyword, for bidirectional mapping. +Bimap has some additional protections on it to ensure a +known state for the connection, whereas the map keyword is +designed to allocate an address and a source port and +rewrite the packet and go on with life. + + bimap tun0 192.168.1.1/32 -> 20.20.20.1/32 + +will accomplish the mapping for one host. + +4.4. Spoofing Services + + Spoofing services? What does that have to do with any- +thing? Plenty. Let's pretend that we have a web server +running on 20.20.20.5, and since we've gotten increasingly +suspicious of our network security, we desire to not run +this server on port 80 since that requires a brief lifespan +as the root user. But how do we run it on a less +privledged port of 8000 in this world of "anything dot com"? +How will anyone find our server? We can use the redirection +facilities of NAT to solve this problem by instructing it to +remap any connections destined for 20.20.20.5:80 to really +point to 20.20.20.5:8000. This uses the rdr keyword: + + rdr tun0 20.20.20.5/32 port 80 -> 192.168.0.5 port 8000 + + + + + + + + + + -28- + + +We can also specify the protocol here, if we wanted to redi- +rect a UDP service, instead of a TCP service (which is the +default). For example, if we had a honeypot on our firewall +to impersonate the popular Back Orifice for Windows, we +could shovel our entire network into this one place with a +simple rule: + + rdr tun0 20.20.20.0/24 port 31337 -> 127.0.0.1 port 31337 udp + +An extremely important point must be made about rdr: You +cannot easily use this feature as a "reflector". E.g: + + rdr tun0 20.20.20.5/32 port 80 -> 20.20.20.6 port 80 tcp + +will not work in the situation where .5 and .6 are on the +same LAN segment. The rdr function is applied to packets +that enter the firewall on the specified interface. When a +packet comes in that matches a rdr rule, its destination +address is then rewritten, it is pushed into ipf for filter- +ing, and should it successfully run the gauntlet of filter +rules, it is then sent to the unix routing code. Since this +packet is still inbound on the same interface that it will +need to leave the system on to reach a host, the system gets +confused. Reflectors don't work. Neither does specifying +the address of the interface the packet just came in on. +Always remember that rdr destinations must exit out of the +firewall host on a different interface. + +4.5. Transparent Proxy Support; Redirection Made Useful + + Since you're installing a firewall, you may have +decided that it is prudent to use a proxy for many of your +outgoing connections so that you can further tighten your +filter rules protecting your internal network, or you may +have run into a situation that the NAT mapping process does +not currently handle properly. This can also be accom- +plished with a redirection statement: + + rdr xl0 0.0.0.0/0 port 21 -> 127.0.0.1 port 21 + +This statement says that any packet coming in on the xl0 +interface destined for any address (0.0.0.0/0) on the ftp +port should be rewritten to connect it with a proxy that is +running on the NAT system on port 21. + +----------- + Yes. There is a way to do this. It's so convo- +luted that I refuse to use it, though. Smart peo- +ple who require this functionality will transpar- +ently redirect into something like TIS plug-gw on +127.0.0.1. Stupid people will set up a dummy loop +interface pair and double rewrite. + This includes 127.0.0.1, by the way. That's on +lo0. Neat, huh? + + + + + + + + + + -29- + + + This specific example of FTP proxying does lead to some +complications when used with web browsers or other auto- +matic-login type clients that are unaware of the require- +ments of communicating with the proxy. There are patches +for TIS Firewall Toolkit'sftp-gw to mate it with the nat +process so that it can determine where you were trying to go +and automatically send you there. Many proxy packages now +work in a transparent proxy environment (Squid for example, +located at http://squid.nlanr.net, works fine.) + + This application of the rdr keyword is often more use- +ful when you wish to force users to authenticate themselves +with the proxy. (For example, you desire your engineers to +be able to surf the web, but you would rather not have your +call-center staff doing so.) + +4.6. Magic Hidden Within NAT; Application Proxies + + Since ipnat provides a method to rewrite packets as +they traverse the firewall, it becomes a convenient place to +build in some application level proxies to make up for well +known deficiencies of that application and typical fire- +walls. For example; FTP. We can make our firewall pay +attention to the packets going across it and when it notices +that it's dealing with an Active FTP session, it can write +itself some temporary rules, much like what happens with +keep state, so that the FTP data connection works. To do +this, we use a rule like so: + + map tun0 192.168.1.0/24 -> 20.20.20.1/32 proxy port ftp ftp/tcp + +You must always remember to place this proxy rule before any +portmap rules, otherwise when portmap comes along and +matches the packet and rewrites it before the proxy gets a +chance to work on it. Remember that ipnat rules are first- +match. + + There also exist proxies for "rcmd" (which we suspect +is berkeley r-* commands which should be forbidden anyway, +thus we haven't looked at what this proxy does) and "raudio" +for Real Audio PNM streams. Likewise, both of these rules +should be put before any portmap rules, if you're doing NAT. + + + +5. Loading and Manipulating Filter Rules; The ipf Utility + + IP Filter rules are loaded by using the ipf utility. +The filter rules can be stored in any file on the system, +but typically these rules are stored in /etc/ipf.rules, +/usr/local/etc/ipf.rules, or /etc/opt/ipf/ipf.rules. + + IP Filter has two sets of rules, the active set and the +inactive set. By default, all operations are performed on + + + + + + + + + + -30- + + +the active set. You can manipulate the inactive set by +adding -I to the ipf command line. The two sets can be +toggled by using the -s command line option. This is very +useful for testing new rule sets without wiping out the old +rule set. + + Rules can also be removed from the list instead of +added by using the -r command line option, but it is gener- +ally a safer idea to flush the rule set that you're working +on with -F and completely reload it when making changes. + + In summary, the easiest way to load a rule set is ipf +-Fa -f /etc/ipf.rules. For more complicated manipulations +of the rule set, please see the ipf(1) man page. + +6. Loading and Manipulating NAT Rules; The ipnat Utility + + NAT rules are loaded by using the ipnat utility. The +NAT rules can be stored in any file on the system, but typi- +cally these rules are stored in /etc/ipnat.rules, +/usr/local/etc/ipnat.rules, or /etc/opt/ipf/ipnat.rules. + + Rules can also be removed from the list instead of +added by using the -r command line option, but it is gener- +ally a safer idea to flush the rule set that you're working +on with -C and completely reload it when making changes. +Any active mappings are not affected by -C, and can be +removed with -F. + + NAT rules and active mappings can be examined with the +-l command line option. + + In summary, the easiest way to load a NAT rule set is +ipnat -CF -f /etc/ipnat.rules. + +7. Monitoring and Debugging + + There will come a time when you are interested in what +your firewall is actually doing, and ipfilter would be +incomplete if it didn't have a full suite of status monitor- +ing tools. + +7.1. The ipfstat utility + + In its simplest form, ipfstat displays a table of +interesting data about how your firewall is performing, such +as how many packets have been passed or blocked, if they +were logged or not, how many state entries have been made, +and so on. Here's an example of something you might see +from running the tool: + + # ipfstat + input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0 + output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0 + + + + + + + + + + -31- + + + input packets logged: blocked 99286 passed 0 + output packets logged: blocked 0 passed 0 + packets logged: input 0 output 0 + log failures: input 3898 output 0 + fragment state(in): kept 0 lost 0 + fragment state(out): kept 0 lost 0 + packet state(in): kept 169364 lost 0 + packet state(out): kept 431395 lost 0 + ICMP replies: 0 TCP RSTs sent: 0 + Result cache hits(in): 1215208 (out): 1098963 + IN Pullups succeeded: 2 failed: 0 + OUT Pullups succeeded: 0 failed: 0 + Fastroute successes: 0 failures: 0 + TCP cksum fails(in): 0 (out): 0 + Packet log flags set: (0) + none + +ipfstat is also capable of showing you your current rule +list. Using the -i or the -o flag will show the currently +loaded rules for in or out, respectively. Adding a -h to +this will provide more useful information at the same time +by showing you a "hit count" on each rule. For example: + + # ipfstat -ho + 2451423 pass out on xl0 from any to any + 354727 block out on ppp0 from any to any + 430918 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags + +From this, we can see that perhaps there's something abnor- +mal going on, since we've got a lot of blocked packets out- +bound, even with a very permissive pass out rule. Something +here may warrant further investigation, or it may be func- +tioning perfectly by design. ipfstat can't tell you if your +rules are right or wrong, it can only tell you what is hap- +pening because of your rules. + +To further debug your rules, you may want to use the -n +flag, which will show the rule number next to each rule. + + # ipfstat -on + @1 pass out on xl0 from any to any + @2 block out on ppp0 from any to any + @3 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags + +The final piece of really interesting information that ipfs- +tat can provide us is a dump of the state table. This is +done with the -s flag: + + # ipfstat -s + 281458 TCP + 319349 UDP + 0 ICMP + 19780145 hits + 5723648 misses + + + + + + + + + + -32- + + + 0 maximum + 0 no memory + 1 active + 319349 expired + 281419 closed + 100.100.100.1 -> 20.20.20.1 ttl 864000 pass 20490 pr 6 state 4/4 + pkts 196 bytes 17394 987 -> 22 585538471:2213225493 16592:16500 + pass in log quick keep state + pkt_flags & b = 2, pkt_options & ffffffff = 0 + pkt_security & ffff = 0, pkt_auth & ffff = 0 + +Here we see that we have one state entry for a TCP connec- +tion. The output will vary slightly from version to ver- +sion, but the basic information is the same. We can see in +this connection that we have a fully established connection +(represented by the 4/4 state. Other states are incomplete +and will be documented fully later.) We can see that the +state entry has a time to live of 240 hours, which is an +absurdly long time, but is the default for an established +TCP connection. This TTL counter is decremented every sec- +ond that the state entry is not used, and will finally +result in the connection being purged if it has been left +idle. The TTL is also reset to 864000 whenever the state +IS used, ensuring that the entry will not time out while it +is being actively used. We can also see that we have passed +196 packets consisting of about 17kB worth of data over this +connection. We can see the ports for both endpoints, in +this case 987 and 22; which means that this state entry rep- +resents a connection from 100.100.100.1 port 987 to +20.20.20.1 port 22. The really big numbers in the second +line are the TCP sequence numbers for this connection, which +helps to ensure that someone isn't easily able to inject a +forged packet into your session. The TCP window is also +shown. The third line is a synopsis of the implicit rule +that was generated by the keep state code, showing that this +connection is an inbound connection. + +7.2. The ipmon utility + + ipfstat is great for collecting snapshots of what's +going on on the system, but it's often handy to have some +kind of log to look at and watch events as they happen in +time. ipmon is this tool. ipmon is capable of watching +the packet log (as created with the log keyword in your +rules), the state log, or the nat log, or any combination of +the three. This tool can either be run in the foreground, +or as a daemon which logs to syslog or a file. If we wanted +to watch the state table in action, ipmon -o S would show +this: + + # ipmon -o S + 01/08/1999 15:58:57.836053 STATE:NEW 100.100.100.1,53 -> 20.20.20.15,53 PR udp + 01/08/1999 15:58:58.030815 STATE:NEW 20.20.20.15,123 -> 128.167.1.69,123 PR udp + 01/08/1999 15:59:18.032174 STATE:NEW 20.20.20.15,123 -> 128.173.14.71,123 PR udp + + + + + + + + + + -33- + + + 01/08/1999 15:59:24.570107 STATE:EXPIRE 100.100.100.1,53 -> 20.20.20.15,53 PR udp Pkts 4 Bytes 356 + 01/08/1999 16:03:51.754867 STATE:NEW 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp + 01/08/1999 16:04:03.070127 STATE:EXPIRE 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp Pkts 63 Bytes 4604 + +Here we see a state entry for an external dns request off +our nameserver, two xntp pings to well-known time servers, +and a very short lived outbound ssh connection. + + ipmon is also capable of showing us what packets have +been logged. For example, when using state, you'll often +run into packets like this: + + # ipmon -o I + 15:57:33.803147 ppp0 @0:2 b 100.100.100.103,443 -> 20.20.20.10,4923 PR tcp len 20 1488 -A + +What does this mean? The first field is obvious, it's a +timestamp. The second field is also pretty obvious, it's +the interface that this event happened on. The third field +@0:2 is something most people miss. This is the rule that +caused the event to happen. Remember ipfstat -in? If you +wanted to know where this came from, you could look there +for rule 2 in rule group 0. The fourth field, the little +"b" says that this packet was blocked, and you'll generally +ignore this unless you're logging passed packets as well, +which would be a little "p" instead. The fifth and sixth +fields are pretty self-explanatory, they say where this +packet came from and where it was going. The seventh ("PR") +and eighth fields tell you the protocol and the ninth field +tells you the size of the packet. The last part, the "-A" +in this case, tells you the flags that were on the packet; +This one was an ACK packet. Why did I mention state ear- +lier? Due to the often laggy nature of the Internet, some- +times packets will be regenerated. Sometimes, you'll get +two copies of the same packet, and your state rule which +keeps track of sequence numbers will have already seen this +packet, so it will assume that the packet is part of a dif- +ferent connection. Eventually this packet will run into a +real rule and have to be dealt with. You'll often see the +last packet of a session being closed get logged because the +keep state code has already torn down the connection before +the last packet has had a chance to make it to your fire- +wall. This is normal, do not be alarmed. Another example +packet that might be logged: + + 12:46:12.470951 xl0 @0:1 S 20.20.20.254 -> 255.255.255.255 PR icmp len 20 9216 icmp 9/0 + +----------- + For a technical presentation of the IP Filter +stateful inspection engine, please see the white +paper Real Stateful TCP Packet Filtering in IP +Filter, by Guido van Rooij. This paper may be +found at +<http://www.iae.nl/users/guido/papers/tcp_filter- +ing.ps.gz> + + + + + + + + + + -34- + + +This is an ICMP router discovery broadcast. We can tell by +the ICMP type 9/0. + +Finally, ipmon also lets us look at the NAT table in action. + + # ipmon -o N + 01/08/1999 05:30:02.466114 @2 NAT:RDR 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816] + 01/08/1999 05:30:31.990037 @2 NAT:EXPIRE 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816] Pkts 10 Bytes 455 + +This would be a redirection to an identd that lies to pro- +vide ident service for the hosts behind our NAT, since they +are typically unable to provide this service for themselves +with ordinary natting. + + + + +8. Specific Applications of IP Filter - Things that don't +fit, but should be mentioned anyway. + +8.1. Keep State With Servers and Flags. + + Keeping state is a good thing, but it's quite easy to +make a mistake in the direction that you want to keep state +in. Generally, you want to have a keep state keyword on +the first rule that interacts with a packet for the connec- +tion. One common mistake that is made when mixing state +tracking with filtering on flags is this: + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S + pass out all keep state + +That certainly appears to allow a connection to be created +to the telnet server on 20.20.20.20, and the replies to go +back. If you try using this rule, you'll see that it does +work--Momentarily. Since we're filtering for the SYN flag, +the state entry never fully gets completed, and the default +time to live for an incomplete state is 60 seconds. + +We can solve this by rewriting the rules in one of two ways: + +1) + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 keep state + block out all + +or: + +2) + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S keep state + + + + + + + + + + -35- + + + pass out all keep state + +Either of these sets of rules will result in a fully estab- +lished state entry for a connection to your server. + +8.2. Coping With FTP + + FTP is one of those protocols that you just have to sit +back and ask "What the heck were they thinking?" FTP has +many problems that the firewall administrator needs to deal +with. What's worse, the problems the administrator must +face are different between making ftp clients work and mak- +ing ftp servers work. + + Within the FTP protocol, there are two forms of data +transfer, called active and passive. Active transfers are +those where the server connects to an open port on the +client to send data. Conversely, passive transfers are +those where the client connects to the server to receive +data. + +8.2.1. Running an FTP Server + + In running an FTP server, handling Active FTP sessions +is easy to setup. At the same time, handling Passive FTP +sessions is a big problem. First we'll cover how to handle +Active FTP, then move on to Passive. Generally, we can han- +dle Active FTP sessions like we would an incoming HTTP or +SMTP connection; just open the ftp port and let keep state +do the rest: + + pass in quick proto tcp from any to 20.20.20.20/32 port = 21 flags S keep state + pass out proto tcp all keep state + +These rules will allow Active FTP sessions, the most common +type, to your ftp server on 20.20.20.20. + + The next challenge becomes handling Passive FTP connec- +tions. Web browsers default to this mode, so it's becoming +quite popular and as such it should be supported. The prob- +lem with passive connections are that for every passive con- +nection, the server starts listening on a new port (usually +above 1023). This is essentially like creating a new +unknown service on the server. Assuming we have a good +firewall with a default-deny policy, that new service will +be blocked, and thus Active FTP sessions are broken. Don't +despair! There's hope yet to be had. + + A person's first inclination to solving this problem +might be to just open up all ports above 1023. In truth, +this will work: + + pass in quick proto tcp from any to 20.20.20.20/32 port > 1023 flags S keep state + pass out proto tcp all keep state + + + + + + + + + + -36- + + +This is somewhat unsatisfactory, though. By letting every- +thing above 1023 in, we actually open ourselves up for a +number of potential problems. While 1-1023 is the desig- +nated area for server services to run, numerous programs +decided to use numbers higher than 1023, such as nfsd and X. + + The good news is that your FTP server gets to decide +which ports get assigned to passive sessions. This means +that instead of opening all ports above 1023, you can allo- +cate ports 15001-19999 as ftp ports and only open that range +of your firewall up. In wu-ftpd, this is done with the pas- +sive ports option in ftpaccess. Please see the man page on +ftpaccess for details in wu-ftpd configuration. On the +ipfilter side, all we need do is setup corresponding rules: + + pass in quick proto tcp from any to 20.20.20.20/32 port 15000 >< 20000 flags S keep state + pass out proto tcp all keep state + +If even this solution doesn't satisfy you, you can always +hack IPF support into your FTP server, or FTP server support +into IPF. + +8.2.2. Running an FTP Client + + While FTP server support is still less than perfect in +IPF, FTP client support has been working well since 3.3.3. +As with FTP servers, there are two types of ftp client +transfers: passive and active. + + The simplest type of client transfer from the fire- +wall's standpoint is the passive transfer. Assuming you're +keeping state on all outbound tcp sessions, passive trans- +fers will work already. If you're not doing this already, +please consider the following: + + pass out proto tcp all keep state + +The second type of client transfer, active, is a bit more +troublesome, but nonetheless a solved problem. Active +transfers cause the server to open up a second connection +back to the client for data to flow through. This is nor- +mally a problem when there's a firewall in the middle, stop- +ping outside connections from coming back in. To solve +this, ipfilter includes an ipnat proxy which temporarily +opens up a hole in the firewall just for the FTP server to +get back to the client. Even if you're not using ipnat to +do nat, the proxy is still effective. The following rules +is the bare minimum to add to the ipnat configuration file +(ep0 should be the interface name of the outbound network +connection): + + map ep0 0/0 -> 0/32 proxy port 21 ftp/tcp + + + + + + + + + + + + -37- + + +For more details on ipfilter's internal proxies, see section +3.6 + +8.3. Assorted Kernel Variables + + There are some useful kernel tunes that either need to +be set for ipf to function, or are just generally handy to +know about for building firewalls. The first major one you +must set is to enable IP Forwarding, otherwise ipf will do +very little, as the underlying ip stack won't actually route +packets. + +IP Forwarding: + +openbsd: + net.inet.ip.forwarding=1 + + +freebsd: + net.inet.ip.forwarding=1 + + +netbsd: + net.inet.ip.forwarding=1 + + +solaris: + ndd -set /dev/ip ip_forwarding 1 + +Ephemeral Port Adjustment: + +openbsd: + net.inet.ip.portfirst = 25000 + + +freebsd: + net.inet.ip.portrange.first = 25000 net.inet.ip.por- + trange.last = 49151 + + +netbsd: + net.inet.ip.anonportmin = 25000 net.inet.ip.anonportmax + = 49151 + + +solaris: + ndd -set /dev/tcp tcp_smallest_anon_port 25000 + ndd -set /dev/tcp tcp_largest_anon_port 65535 + +Other Useful Values: + +openbsd: + net.inet.ip.sourceroute = 0 + net.inet.ip.directed-broadcast = 0 + + + + + + + + + + -38- + + +freebsd: + net.inet.ip.sourceroute=0 + net.ip.accept_sourceroute=0 + + +netbsd: + net.inet.ip.allowsrcrt=0 + net.inet.ip.forwsrcrt=0 + net.inet.ip.directed-broadcast=0 + net.inet.ip.redirect=0 + + +solaris: + ndd -set /dev/ip ip_forward_directed_broadcasts 0 + ndd -set /dev/ip ip_forward_src_routed 0 + ndd -set /dev/ip ip_respond_to_echo_broadcast 0 + +In addition, freebsd has some ipf specific sysctl variables. + + net.inet.ipf.fr_flags: 0 + net.inet.ipf.fr_pass: 514 + net.inet.ipf.fr_active: 0 + net.inet.ipf.fr_tcpidletimeout: 864000 + net.inet.ipf.fr_tcpclosewait: 60 + net.inet.ipf.fr_tcplastack: 20 + net.inet.ipf.fr_tcptimeout: 120 + net.inet.ipf.fr_tcpclosed: 1 + net.inet.ipf.fr_udptimeout: 120 + net.inet.ipf.fr_icmptimeout: 120 + net.inet.ipf.fr_defnatage: 1200 + net.inet.ipf.fr_ipfrttl: 120 + net.inet.ipf.ipl_unreach: 13 + net.inet.ipf.ipl_inited: 1 + net.inet.ipf.fr_authsize: 32 + net.inet.ipf.fr_authused: 0 + net.inet.ipf.fr_defaultauthage: 600 + + + + +9. Fun with ipf! + + This section doesn't necessarily teach you anything new +about ipf, but it may raise an issue or two that you haven't +yet thought up on your own, or tickle your brain in a way +that you invent something interesting that we haven't +thought of. + +9.1. Localhost Filtering + + A long time ago at a university far, far away, Wietse +Venema created the tcp-wrapper package, and ever since, it's +been used to add a layer of protection to network services +all over the world. This is good. But, tcp-wrappers have + + + + + + + + + + -39- + + +flaws. For starters, they only protect TCP services, as the +name suggests. Also, unless you run your service from +inetd, or you have specifically compiled it with libwrap and +the appropriate hooks, your service isn't protected. This +leaves gigantic holes in your host security. We can plug +these up by using ipf on the local host. For example, my +laptop often gets plugged into or dialed into networks that +I don't specifically trust, and so, I use the following rule +set: + + pass in quick on lo0 all + pass out quick on lo0 all + + block in log all + block out all + + pass in quick proto tcp from any to any port = 113 flags S keep state + pass in quick proto tcp from any to any port = 22 flags S keep state + pass in quick proto tcp from any port = 20 to any port 39999 >< 45000 flags S keep state + + pass out quick proto icmp from any to any keep state + pass out quick proto tcp/udp from any to any keep state keep frags + +It's been like that for quite a while, and I haven't suf- +fered any pain or anguish as a result of having ipf loaded +up all the time. If I wanted to tighten it up more, I could +switch to using the NAT ftp proxy and I could add in some +rules to prevent spoofing. But even as it stands now, this +box is far more restrictive about what it presents to the +local network and beyond than the typical host does. This +is a good thing if you happen to run a machine that allows a +lot of users on it, and you want to make sure one of them +doesn't happen to start up a service they wern't supposed +to. It won't stop a malicious hacker with root access from +adjusting your ipf rules and starting a service anyway, but +it will keep the "honest" folks honest, and your weird ser- +vices safe, cozy and warm even on a malicious LAN. A big +win, in my opinion. Using local host filtering in addition +to a somewhat less-restrictive "main firewall" machine can +solve many performance issues as well as political night- +mares like "Why doesn't ICQ work?" and "Why can't I put a +web server on my own workstation! It's MY WORKSTATION!!" +Another very big win. Who says you can't have security and +convienence at the same time? + +9.2. What Firewall? Transparent filtering. + + One major concern in setting up a firewall is the +integrity of the firewall itself. Can somebody break into +your firewall, thereby subverting its ruleset? This is a +common problem administrators must face, particularly when +they're using firewall solutions on top of their Unix/NT +machines. Some use it as an argument for blackbox hardware +solutions, under the flawed notion that inherent obscurity + + + + + + + + + + -40- + + +of their closed system increases their security. We have a +better way. + + Many network admins are familiar with the common ether- +net bridge. This is a device that connects two separate +ethernet segments to make them one. An ethernet bridge is +typically used to connect separate buildings, switch network +speeds, and extend maximum wire lengths. Hubs and switches +are common bridges, sometimes they're just 2 ported devices +called repeaters. Recent versions of Linux, OpenBSD, +NetBSD, and FreeBSD include code to convert $1000 PCs into +$10 bridges, too! What all bridges tend to have in common +is that though they sit in the middle of a connection +between two machines, the two machines don't know the bridge +is there. Enter ipfilter and OpenBSD. + + Ethernet bridging takes place at Layer2 on the ISO +stack. IP takes place on Layer3. IP Filter in primarily +concerned with Layer3, but dabbles in Layer2 by working with +interfaces. By mixing IP filter with OpenBSD's bridge +device, we can create a firewall that is both invisible and +unreachable. The system needs no IP address, it doesn't +even need to reveal its ethernet address. The only telltale +sign that the filter might be there is that latency is some- +what higher than a piece of cat5 would normally make it, and +that packets don't seem to make it to their final destina- +tion. + + The setup for this sort of ruleset is surprisingly sim- +ple, too. In OpenBSD, the first bridge device is named +bridge0. Say we have two ethernet cards in our machine as +well, xl0 and xl1. To turn this machine into a bridge, all +one need do is enter the following three commands: + + brconfig bridge0 add xl0 add xl1 up + ifconfig xl0 up + ifconfig xl1 up + +At ths point, all traffic ariving on xl0 is sent out xl1 and +all traffic on xl1 is sent out xl0. You'll note that nei- +ther interface has been assigned an IP address, nor do we +need assign one. All things considered, it's likely best we +not add one at all. + + Rulesets behave essentially the as the always have. +Though there is a bridge0 interface, we don't filter based +on it. Rules continue to be based upon the particular +interface we're using, making it important which network +cable is plugged into which network card in the back of the +machine. Let's start with some basic filtering to illis- +trate what's happened. Assume the network used to look like +this: + + + + + + + + + + + + -41- + + + 20.20.20.1 <---------------------------------> 20.20.20.0/24 network hub + +That is, we have a router at 20.20.20.1 connected to the +20.20.20.0/24 network. All packets from the 20.20.20.0/24 +network go through 20.20.20.1 to get to the outside world +and vice versa. Now we add the Ipf Bridge: + + 20.20.20.1 <-------/xl0 IpfBridge xl1/-------> 20.20.20.0/24 network hub + +We also have the following ruleset loaded on the IpfBridge +host: + + pass in quick all + pass out quick all + +With this ruleset loaded, the network is functionally iden- +tical. As far as the 20.20.20.1 router is concerned, and as +far as the 20.20.20.0/24 hosts are concerned, the two net- +work diagrams are identical. Now let's change the ruleset +some: + + block in quick on xl0 proto icmp + pass in quick all + pass out quick all + +Still, 20.20.20.1 and 20.20.20.0/24 think the network is +identical, but if 20.20.20.1 attempts to ping 20.20.20.2, it +will never get a reply. What's more, 20.20.20.2 won't even +get the packet in the first place. IPfilter will intercept +the packet before it even gets to the other end of the vir- +tual wire. We can put a bridged filter anywhere. Using +this method we can shrink the network trust circle down an +individual host level (given enough ethernet cards:-) + + Blocking icmp from the world seems kind of silly, espe- +cially if you're a sysadmin and like pinging the world, to +traceroute, or to resize your MTU. Let's construct a better +ruleset and take advantage of the original key feature of +ipf: stateful inspection. + + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl0 + +In this situation, the 20.20.20.0/24 network (perhaps more +aptly called the xl1 network) can now reach the outside +world, but the outside world can't reach it, and it can't +figure out why, either. The router is accessible, the hosts +are active, but the outside world just can't get in. Even +if the router itself were compromised, the firewall would +still be active and successful. + + + + + + + + + + + + -42- + + + So far, we've been filtering by interface and protocol +only. Even though bridging is concerned layer2, we can +still discriminate based on IP address. Normally we have a +few services running, so our ruleset may look like this: + + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir. + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + +Now we have a network where 20.20.20.2 is a zone serving +name server, 20.20.20.3 is an incoming mail server, and +20.20.20.7 is a web server. + + Bridged IP Filter is not yet perfect, we must confess. + + First, You'll note that all the rules are setup using +the in direction instead of a combination of in and out. +This is because the out direction is presently unimplemented +with bridging in OpenBSD. This was originally done to pre- +vent vast performance drops using multiple interfaces. Work +has been done in speeding it up, but it remains unimple- +mented. If you really want this feature, you might try your +hand at working on the code or asking the OpenBSD people how +you can help. + + Second, using IP Filter with bridging makes the use of +IPF's NAT features inadvisable, if not downright dangerous. +The first problem is that it would give away that there's a +filtering bridge. The second problem would be that the +bridge has no IP address to masquerade with, which will most +assuredly lead to confusion and perhaps a kernel panic to +boot. You can, of course, put an IP address on the outbound +interface to make NAT work, but part of the glee of bridging +is thus diminished. + +9.2.1. Using Transparent Filtering to Fix Network Design +Mistakes + + Many organizations started using IP well before they +thought a firewall or a subnet would be a good idea. Now +they have class-C sized networks or larger that include all +their servers, their workstations, their routers, coffee +makers, everything. The horror! Renumbering with proper +subnets, trust levels, filters, and so are in both time con- +suming and expensive. The expense in hardware and man hours +alone is enough to make most organizations unwilling to +really solve the problem, not to mention the downtime +involved. The typical problem network looks like this: + + + + + + + + + + -43- + + + 20.20.20.1 router 20.20.20.6 unix server + 20.20.20.2 unix server 20.20.20.7 nt workstation + 20.20.20.3 unix server 20.20.20.8 nt server + 20.20.20.4 win98 workstation 20.20.20.9 unix workstation + 20.20.20.5 intelligent switch 20.20.20.10 win95 workstation + +Only it's about 20 times larger and messier and frequently +undocumented. Ideally, you'd have all the trusting servers +in one subnet, all the work- stations in another, and the +network switches in a third. Then the router would filter +packets between the subnets, giving the workstations limited +access to the servers, nothing access to the switches, and +only the sysadmin's workstation access to the coffee pot. +I've never seen a class-C sized network with such coherence. +IP Filter can help. + + To start with, we're going to separate the router, the +workstations, and the servers. To do this we're going to +need 2 hubs (or switches) which we probably already have, +and an IPF machine with 3 ethernet cards. We're going to +put all the servers on one hub and all the workstations on +the other. Normally we'd then connect the hubs to each +other, then to the router. Instead, we're going to plug the +router into IPF's xl0 interface, the servers into IPF's xl1 +interface, and the workstations into IPF's xl2 interface. +Our network diagram looks something like this: + + | 20.20.20.2 unix server + router (20.20.20.1) ____________| 20.20.20.3 unix server + | / | 20.20.20.6 unix server + | /xl1 | 20.20.20.7 nt server + ------------/xl0 IPF Bridge < + xl2 | 20.20.20.4 win98 workstation + ____________| 20.20.20.8 nt workstation + | 20.20.20.9 unix workstation + | 20.20.20.10 win95 workstation + +Where once there was nothing but interconnecting wires, now +there's a filtering bridge that not a single host needs to +be modified to take advantage of. Presumably we've already +enabled bridging so the network is behaving perfectly nor- +mally. Further, we're starting off with a ruleset much like +our last ruleset: + + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir. + pass in quick on xl2 proto tcp keep state + + + + + + + + + + -44- + + + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Once again, traffic coming from the router is restricted to +DNS, SMTP, and HTTP. At the moment, the servers and the +workstations can exchange traffic freely. Depending on what +kind of organization you are, there might be something about +this network dynamic you don't like. Perhaps you don't want +your workstations getting access to your servers at all? +Take the xl2 ruleset of: + + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +And change it to: + + block in quick on xl2 from any to 20.20.20.0/24 + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Perhaps you want them to just get to the servers to get and +send their mail with IMAP? Easily done: + + pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=25 + pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=143 + block in quick on xl2 from any to 20.20.20.0/24 + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Now your workstations and servers are protected from the +outside world, and the servers are protected from your work- +stations. + + Perhaps the opposite is true, maybe you want your work- +stations to be able to get to the servers, but not the out- +side world. After all, the next generation of exploits is +breaking the clients, not the servers. In this case, you'd +change the xl2 rules to look more like this: + + pass in quick on xl2 from any to 20.20.20.0/24 + block in quick on xl2 + +Now the servers have free reign, but the clients can only +connect to the servers. We might want to batten down the +hatches on the servers, too: + + pass in quick on xl1 from any to 20.20.20.0/24 + + + + + + + + + + -45- + + + block in quick on xl1 + +With the combination of these two, the clients and servers +can talk to each other, but neither can access the outside +world (though the outside world can get to the few services +from earlier). The whole ruleset would look something like +this: + + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + pass in quick on xl1 from any to 20.20.20.0/24 + block in quick on xl1 + pass in quick on xl2 from any to 20.20.20.0/24 + block in quick on xl2 + +So remember, when your network is a mess of twisty IP +addresses and machine classes, transparent filtered bridges +can solve a problem that would otherwise be lived with and +perhaps someday exploited. + +9.3. Drop-Safe Logging With dup-to and to. + + Until now, we've been using the filter to drop packets. +Instead of dropping them, let's consider passing them on to +another system that can do something useful with this infor- +mation beyond the logging we can perform with ipmon. Our +firewall system, be it a bridge or a router, can have as +many interfaces as we can cram into the system. We can use +this information to create a "drop-safe" for our packets. A +good example of a use for this would be to implement an +intrusion detection network. For starters, it might be +desirable to hide the presence of our intrusion detection +systems from our real network so that we can keep them from +being detected. + + Before we get started, there are some operational char- +acteristics that we need to make note of. If we are only +going to deal with blocked packets, we can use either the to +keyword or the fastroute keyword. (We'll cover the differ- +ences between these two later) If we're going to pass the +packets like we normally would, we need to make a copy of +the packet for our drop-safe log with the dup-to keyword. + +9.3.1. The dup-to Method + + If, for example, we wanted to send a copy of everything +going out the xl3 interface off to our drop-safe network on +ed0, we would use this rule in our filter list: + + pass out on xl3 dup-to ed0 from any to any + + + + + + + + + + + -46- + + +You might also have a need to send the packet directly to a +specific IP address on your drop-safe network instead of +just making a copy of the packet out there and hoping for +the best. To do this, we modify our rule slightly: + + pass out on xl3 dup-to ed0:192.168.254.2 from any to any + +But be warned that this method will alter the copied +packet's destination address, and may thus destroy the use- +fulness of the log. For this reason, we recommend only +using the known address method of logging when you can be +certain that the address that you're logging to corresponds +in some way to what you're logging for (e.g.: don't use +"192.168.254.2" for logging for both your web server and +your mail server, since you'll have a hard time later trying +to figure out which system was the target of a specific set +of packets.) + + This technique can be used quite effectively if you +treat an IP Address on your drop-safe network in much the +same way that you would treat a Multicast Group on the real +internet. (e.g.: "192.168.254.2" could be the channel for +your http traffic analysis system, "23.23.23.23" could be +your channel for telnet sessions, and so on.) You don't +even need to actually have this address set as an address or +alias on any of your analysis systems. Normally, your +ipfilter machine would need to ARP for the new destination +address (using dup-to ed0:192.168.254.2 style, of course) +but we can avoid that issue by creating a static arp entry +for this "channel" on our ipfilter system. + + In general, though, dup-to ed0 is all that is required +to get a new copy of the packet over to our drop-safe net- +work for logging and examination. + +9.3.2. The to Method + + The dup-to method does have an immediate drawback, +though. Since it has to make a copy of the packet and +optionally modify it for its new destination, it's going to +take a while to complete all this work and be ready to deal +with the next packet coming in to the ipfilter system. + + If we don't care about passing the packet to its normal +destination and we were going to block it anyway, we can +just use the to keyword to push this packet past the normal +routing table and force it to go out a different interface +than it would normally go out. + + block in quick on xl0 to ed0 proto tcp from any to any port < 1024 + +we use block quick for to interface routing, because like +fastroute, the to interface code will generate two packet +paths through ipfilter when used with pass, and likely cause + + + + + + + + + + -47- + + +your system to panic. + + + +10. Bogus Network Filtering, the ultimate in current anti- +spoofing technology. + + We've spent a little bit of time tracking down the cur- +rent vast tracts of IP address space that have been reserved +by the IANA for various reasons, or are otherwise not cur- +rently in use at the time this document was written. Since +none of these address ranges should be in use currently, +there should be no legitimate reason to ever see them as a +source address, or to send them traffic as a destination +address, right? Right! + + So without further ado, the complete list of bogus net- +works: + + # + # s/OUTSIDE/outside-interface (eg: fxp0) + # s/MYNET/network-cidr-address (eg: 1.2.3.0/24) + # + block in on OUTSIDE all + block in quick on OUTSIDE from 0.0.0.0/7 to any + block in quick on OUTSIDE from 2.0.0.0/8 to any + block in quick on OUTSIDE from 5.0.0.0/8 to any + block in quick on OUTSIDE from 10.0.0.0/8 to any + block in quick on OUTSIDE from 23.0.0.0/8 to any + block in quick on OUTSIDE from 27.0.0.0/8 to any + block in quick on OUTSIDE from 31.0.0.0/8 to any + block in quick on OUTSIDE from 67.0.0.0/8 to any + block in quick on OUTSIDE from 68.0.0.0/6 to any + block in quick on OUTSIDE from 72.0.0.0/5 to any + block in quick on OUTSIDE from 80.0.0.0/4 to any + block in quick on OUTSIDE from 96.0.0.0/3 to any + block in quick on OUTSIDE from 127.0.0.0/8 to any + block in quick on OUTSIDE from 128.0.0.0/16 to any + block in quick on OUTSIDE from 128.66.0.0/16 to any + block in quick on OUTSIDE from 169.254.0.0/16 to any + block in quick on OUTSIDE from 172.16.0.0/12 to any + block in quick on OUTSIDE from 191.255.0.0/16 to any + block in quick on OUTSIDE from 192.0.0.0/16 to any + block in quick on OUTSIDE from 192.168.0.0/16 to any + block in quick on OUTSIDE from 197.0.0.0/8 to any + block in quick on OUTSIDE from 201.0.0.0/8 to any + block in quick on OUTSIDE from 204.152.64.0/23 to any + block in quick on OUTSIDE from 224.0.0.0/3 to any + block in quick on OUTSIDE from MYNET to any + # Your pass rules come here... + + block out on OUTSIDE all + block out quick on OUTSIDE from !MYNET to any + block out quick on OUTSIDE from MYNET to 0.0.0.0/7 + + + + + + + + + + -48- + + + block out quick on OUTSIDE from MYNET to 2.0.0.0/8 + block out quick on OUTSIDE from MYNET to 5.0.0.0/8 + block out quick on OUTSIDE from MYNET to 10.0.0.0/8 + block out quick on OUTSIDE from MYNET to 23.0.0.0/8 + block out quick on OUTSIDE from MYNET to 27.0.0.0/8 + block out quick on OUTSIDE from MYNET to 31.0.0.0/8 + block out quick on OUTSIDE from MYNET to 67.0.0.0/8 + block out quick on OUTSIDE from MYNET to 68.0.0.0/6 + block out quick on OUTSIDE from MYNET to 72.0.0.0/5 + block out quick on OUTSIDE from MYNET to 80.0.0.0/4 + block out quick on OUTSIDE from MYNET to 96.0.0.0/3 + block out quick on OUTSIDE from MYNET to 127.0.0.0/8 + block out quick on OUTSIDE from MYNET to 128.0.0.0/16 + block out quick on OUTSIDE from MYNET to 128.66.0.0/16 + block out quick on OUTSIDE from MYNET to 169.254.0.0/16 + block out quick on OUTSIDE from MYNET to 172.16.0.0/12 + block out quick on OUTSIDE from MYNET to 191.255.0.0/16 + block out quick on OUTSIDE from MYNET to 192.0.0.0/16 + block out quick on OUTSIDE from MYNET to 192.168.0.0/16 + block out quick on OUTSIDE from MYNET to 197.0.0.0/8 + block out quick on OUTSIDE from MYNET to 201.0.0.0/8 + block out quick on OUTSIDE from MYNET to 204.152.64.0/23 + block out quick on OUTSIDE from MYNET to 224.0.0.0/3 + # Your pass rules come here... + +If you're going to use these, we suggest that you become +familiar with whois.arin.net and keep an occasional eye on +these, as the IANA isn't going to notify you when they allo- +cate one of these to a new corporation or something. You +have been warned. + + We'd also like to thank Frank DiGennaro <fsd@server- +vault.com> for greatly contributing to this filter list. + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/share/examples/ipfilter/ipf.conf.permissive b/share/examples/ipfilter/ipf.conf.permissive new file mode 100644 index 000000000000..016c59cadff2 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.permissive @@ -0,0 +1,29 @@ +# augmented rules generated by mkfilters +block in log quick from any with ipopts +block in log quick proto tcp from any to any with short +block in log quick all with opt lsrr +block in log quick all with opt ssrr +#------------------------------------------------------- +# loopback pakets left unmolested +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +pass out on ed1 all head 150 +block out from 127.0.0.0/8 to any group 150 +block out from any to 127.0.0.0/8 group 150 +block out from any to 192.168.1.110/32 group 150 +#------------------------------------------------------- +pass in on ed1 all head 100 +block in from 127.0.0.0/8 to any group 100 +block in from 192.168.1.110/32 to any group 100 +block in from 192.168.0.1/24 to any group 100 +#------------------------------------------------------- +pass out on fxp0 all head 250 +block out from 127.0.0.0/8 to any group 250 +block out from any to 127.0.0.0/8 group 250 +block out from any to 192.168.0.1/32 group 250 +#------------------------------------------------------- +pass in on fxp0 all head 200 +block in from 127.0.0.0/8 to any group 200 +block in from 192.168.0.1/32 to any group 200 +block in from 192.168.1.110/24 to any group 200 diff --git a/share/examples/ipfilter/ipf.conf.restrictive b/share/examples/ipfilter/ipf.conf.restrictive new file mode 100644 index 000000000000..b1b449c8fd77 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.restrictive @@ -0,0 +1,76 @@ +#-------------------------------------------------------------------------- +# ed1 - external interface +# fxp0 - internal interface +#-------------------------------------------------------------------------- +# First, nasty packets which we don't want near us at all +# packets which are too short to be real except echo replies on lo0 +pass in log quick on lo0 proto icmp from 127.0.0.1/8 to 127.0.0.1/8 with short +block in log quick all with short +block in log quick all with opt lsrr +block in log quick all with opt ssrr +#-------------------------------------------------------------------------- +# loopback packets left unmolested +pass in log quick on lo0 all +pass out log quick on lo0 all +#-------------------------------------------------------------------------- +# Group setup: +# 100 incoming ed1 +# 150 outgoing ed1 +# 200 incoming fxp0 +# 250 outgoing fxp0 +#-------------------------------------------------------------------------- +block in log body on ed1 all head 100 +block out log body on ed1 all head 150 +#-------------------------------------------------------------------------- +block in log on fxp0 all head 200 +block out log on fxp0 all head 250 +#-------------------------------------------------------------------------- +# incoming ed1 traffic - group 100 +# 1) prevent localhost spoofing +block in log quick from 127.0.0.1/32 to 192.168.0.0/24 group 100 +block in log quick from 127.0.0.1/32 to 192.168.1.0/24 group 100 +block in log quick from any to 127.0.0.1/8 group 100 +#-------------------------------------------------------------------------- +# 2) deny pakets which should not be seen on th internet (paranoid) +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from any to 10.0.0.0/8 group 100 +block in log quick from 172.16.0.0/16 to any group 100 +block in log quick from any to 172.16.0.0/16 group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log from any to 192.168.0.0/16 group 100 +# 3) implement policy +# allow incoming ftp-data +pass in log quick proto tcp/udp from any to 192.168.1.1/24 keep state group 100 +# if nothing applies, block and return icmp-replies (unreachable and rst) +block return-icmp(net-unr) in proto udp from any to any group 100 +block return-rst in log proto tcp from any to any group 100 +#-------------------------------------------------------------------------- +# outgoing ed1 traffic - group 150 +# Setup outgoing DNS +pass out log quick proto tcp/udp from any to 212.40.0.10 port = 53 keep state group 150 +pass out log quick proto tcp/udp from any to 212.40.5.50 port = 53 keep state group 150 +# allow outgoing http-service +pass out log quick proto tcp from any to any port = 80 flags S/SA keep state keep frags group 150 +# allow outgoing smtp traffic +pass out log quick proto tcp from 192.168.1.1/24 to any port = 25 flags S/SA keep state group 150 +# allow outgoing pop3 traffic +pass out log quick proto tcp from 192.168.1.1/24 to any port = 110 flags S/SA keep state group 150 +# allow outgoing ftp traffic +pass out log quick proto tcp/udp from 192.168.1.1/24 to any port = ftp keep state group 150 +pass out log quick proto icmp from any to any keep state keep frags group 150 +#-------------------------------------------------------------------------- +# incoming traffic on fxp0 - group 200 +#-------------------------------------------------------------------------- +# 1) prevent localhost spoofing +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from 192.168.0.1/32 to any group 200 +block in log quick from 192.168.1.110/24 to any group 200 +pass in log quick from any to any group 200 +#-------------------------------------------------------------------------- +# outgoing traffic on fxp0 - group 250 +#-------------------------------------------------------------------------- +block out log quick from 127.0.0.0/8 to any group 250 +block out quick from any to 127.0.0.0/8 group 250 +block out log quick from any to 192.168.0.1/32 group 250 +pass out log quick from any to nay group 250 +#-------------------------------------------------------------------------- diff --git a/share/examples/ipfilter/ipf.conf.sample b/share/examples/ipfilter/ipf.conf.sample new file mode 100644 index 000000000000..cb47107f88c5 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.sample @@ -0,0 +1,18 @@ +block in log quick from any with ipopts +block in log quick proto tcp from any to any with short +pass out on ed1 all head 150 +block out from 127.0.0.0/8 to any group 150 +block out from any to 127.0.0.0/8 group 150 +block out from any to 192.168.1.110/32 group 150 +pass in on ed1 all head 100 +block in from 127.0.0.0/8 to any group 100 +block in from 192.168.1.110/32 to any group 100 +block in from 192.168.0.1/0xffffff00 to any group 100 +pass out on fxp0 all head 250 +block out from 127.0.0.0/8 to any group 250 +block out from any to 127.0.0.0/8 group 250 +block out from any to 192.168.0.1/32 group 250 +pass in on fxp0 all head 200 +block in from 127.0.0.0/8 to any group 200 +block in from 192.168.0.1 to any group 200 +block in from 192.168.1.110/0xffffff00 to any group 200 diff --git a/share/examples/ipfilter/ipnat.conf.sample b/share/examples/ipfilter/ipnat.conf.sample new file mode 100644 index 000000000000..f20d895936ef --- /dev/null +++ b/share/examples/ipfilter/ipnat.conf.sample @@ -0,0 +1,2 @@ +map ed1 192.168.0.0/24 -> 192.168.1.110/32 portmap tcp/udp 40000:65000 +map ed1 192.168.0.0/24 -> 192.168.1.110/32 diff --git a/share/examples/ipfilter/l4check/Makefile b/share/examples/ipfilter/l4check/Makefile new file mode 100644 index 000000000000..e7366b63ad6a --- /dev/null +++ b/share/examples/ipfilter/l4check/Makefile @@ -0,0 +1,10 @@ +# For Solaris +#LIBS=-lsocket -lnsl + +all: l4check + +l4check: l4check.c + $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@ + +clean: + /bin/rm -f l4check diff --git a/share/examples/ipfilter/l4check/http.check b/share/examples/ipfilter/l4check/http.check new file mode 100644 index 000000000000..56d93d9281a6 --- /dev/null +++ b/share/examples/ipfilter/l4check/http.check @@ -0,0 +1,2 @@ +GET / + diff --git a/share/examples/ipfilter/l4check/http.ok b/share/examples/ipfilter/l4check/http.ok new file mode 100644 index 000000000000..2b5d2c15266d --- /dev/null +++ b/share/examples/ipfilter/l4check/http.ok @@ -0,0 +1 @@ +<HTML>
\ No newline at end of file diff --git a/share/examples/ipfilter/l4check/l4check.c b/share/examples/ipfilter/l4check/l4check.c new file mode 100644 index 000000000000..2e80b7531b4e --- /dev/null +++ b/share/examples/ipfilter/l4check/l4check.c @@ -0,0 +1,800 @@ + +/* + * (C)Copyright (C) 2012 by Darren Reed. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/if.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" + +#include "ipf.h" + +extern char *optarg; + + +typedef struct l4cfg { + struct l4cfg *l4_next; + struct ipnat l4_nat; /* NAT rule */ + struct sockaddr_in l4_sin; /* remote socket to connect */ + time_t l4_last; /* when we last connected */ + int l4_alive; /* 1 = remote alive */ + int l4_fd; + int l4_rw; /* 0 = reading, 1 = writing */ + char *l4_rbuf; /* read buffer */ + int l4_rsize; /* size of buffer */ + int l4_rlen; /* how much used */ + char *l4_wptr; /* next byte to write */ + int l4_wlen; /* length yet to be written */ +} l4cfg_t; + + +l4cfg_t *l4list = NULL; +char *response = NULL; +char *probe = NULL; +l4cfg_t template; +int frequency = 20; +int ctimeout = 1; +int rtimeout = 1; +size_t plen = 0; +size_t rlen = 0; +int natfd = -1; +int opts = 0; + +#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) +# define strerror(x) sys_errlist[x] +#endif + + +char * +copystr(char *dst, char *src) +{ + register char *s, *t, c; + register int esc = 0; + + for (s = src, t = dst; s && t && (c = *s++); ) + if (esc) { + esc = 0; + switch (c) + { + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + } else if (c != '\\') + *t++ = c; + else + esc = 1; + *t = '\0'; + return(dst); +} + +void +addnat(l4cfg_t *l4) +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ntohs(ipn->in_pmin)); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCADNAT, &ipn) == -1) + perror("ioctl(SIOCADNAT)"); + } +} + + +void +delnat(l4cfg_t *l4) +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Remove NAT rule for %s/%#x,%u -> ", + inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) + perror("ioctl(SIOCRMNAT)"); + } +} + + +void +connectl4(l4cfg_t *l4) +{ + l4->l4_rw = 1; + l4->l4_rlen = 0; + l4->l4_wlen = plen; + if (!l4->l4_wlen) { + l4->l4_alive = 1; + addnat(l4); + } else + l4->l4_wptr = probe; +} + + +void +closel4(l4cfg_t *l4, int dead) +{ + close(l4->l4_fd); + l4->l4_fd = -1; + l4->l4_rw = -1; + if (dead && l4->l4_alive) { + l4->l4_alive = 0; + delnat(l4); + } +} + + +void +connectfd(l4cfg_t *l4) +{ + if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno == EISCONN) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connected fd %d\n", + l4->l4_fd); + connectl4(l4); + return; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connect failed fd %d: %s\n", + l4->l4_fd, strerror(errno)); + closel4(l4, 1); + return; + } + l4->l4_rw = 1; +} + + +void +writefd(l4cfg_t *l4) +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + n = l4->l4_wlen; + + i = send(fd, l4->l4_wptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Send on fd %d failed: %s\n", + fd, strerror(errno)); + closel4(l4, 1); + } else { + l4->l4_wptr += i; + l4->l4_wlen -= i; + if (l4->l4_wlen == 0) + l4->l4_rw = 0; + if (opts & OPT_VERBOSE) + fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); + } +} + + +void readfd(l4cfg_t *l4) +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + if (l4->l4_rsize) { + n = l4->l4_rsize - l4->l4_rlen; + ptr = l4->l4_rbuf + l4->l4_rlen; + } else { + n = sizeof(buf) - 1; + ptr = buf; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read %d bytes on fd %d to %p\n", + n, fd, ptr); + i = recv(fd, ptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read error on fd %d: %s\n", + fd, (i == 0) ? "EOF" : strerror(errno)); + closel4(l4, 1); + } else { + if (ptr == buf) + ptr[i] = '\0'; + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", + fd, i, i, i, ptr); + if (ptr != buf) { + l4->l4_rlen += i; + if (l4->l4_rlen >= l4->l4_rsize) { + if (!strncmp(response, l4->l4_rbuf, + l4->l4_rsize)) { + printf("%d: Good response\n", + fd); + if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + } + closel4(l4, 0); + } else { + if (opts & OPT_VERBOSE) + printf("%d: Bad response\n", + fd); + closel4(l4, 1); + } + } + } else if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + closel4(l4, 0); + } + } +} + + +int +runconfig(void) +{ + int fd, opt, res, mfd, i; + struct timeval tv; + time_t now, now1; + fd_set rfd, wfd; + l4cfg_t *l4; + + mfd = 0; + opt = 1; + now = time(NULL); + + /* + * First, initiate connections that are closed, as required. + */ + for (l4 = l4list; l4; l4 = l4->l4_next) { + if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { + l4->l4_last = now; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + continue; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)); +#ifdef O_NONBLOCK + if ((res = fcntl(fd, F_GETFL, 0)) != -1) + fcntl(fd, F_SETFL, res | O_NONBLOCK); +#endif + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Connecting to %s,%d (fd %d)...", + inet_ntoa(l4->l4_sin.sin_addr), + ntohs(l4->l4_sin.sin_port), fd); + if (connect(fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno != EINPROGRESS) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "failed\n"); + perror("connect"); + close(fd); + fd = -1; + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "waiting\n"); + l4->l4_rw = -2; + } + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "connected\n"); + connectl4(l4); + } + l4->l4_fd = fd; + } + } + + /* + * Now look for fd's which we're expecting to read/write from. + */ + FD_ZERO(&rfd); + FD_ZERO(&wfd); + tv.tv_sec = MIN(rtimeout, ctimeout); + tv.tv_usec = 0; + + for (l4 = l4list; l4; l4 = l4->l4_next) + if (l4->l4_rw == 0) { + if (now - l4->l4_last > rtimeout) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read timeout\n", + l4->l4_fd); + closel4(l4, 1); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for read on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &rfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } else if ((l4->l4_rw == 1 && l4->l4_wlen) || + l4->l4_rw == -2) { + if ((l4->l4_rw == -2) && + (now - l4->l4_last > ctimeout)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, + "%d: connect timeout\n", + l4->l4_fd); + closel4(l4); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for write on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &wfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, + tv.tv_sec); + i = select(mfd + 1, &rfd, &wfd, NULL, &tv); + if (i == -1) { + perror("select"); + return(-1); + } + + now1 = time(NULL); + + for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { + if (l4->l4_fd < 0) + continue; + if (FD_ISSET(l4->l4_fd, &rfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to read on fd %d\n", + l4->l4_fd); + readfd(l4); + i--; + } + + if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to write on fd %d\n", + l4->l4_fd); + writefd(l4); + i--; + } + } + return(0); +} + + +int +gethostport(char *str, int lnum, u_32_t *ipp, u_short *portp) +{ + struct servent *sp; + struct hostent *hp; + char *host, *port; + struct in_addr ip; + + host = str; + port = strchr(host, ','); + if (port) + *port++ = '\0'; + +#ifdef HAVE_INET_ATON + if (ISDIGIT(*host) && inet_aton(host, &ip)) + *ipp = ip.s_addr; +#else + if (ISDIGIT(*host)) + *ipp = inet_addr(host); +#endif + else { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "%d: can't resolve hostname: %s\n", + lnum, host); + return(0); + } + *ipp = *(u_32_t *)hp->h_addr; + } + + if (port) { + if (ISDIGIT(*port)) + *portp = htons(atoi(port)); + else { + sp = getservbyname(port, "tcp"); + if (sp) + *portp = sp->s_port; + else { + fprintf(stderr, "%d: unknown service %s\n", + lnum, port); + return(0); + } + } + } else + *portp = 0; + return(1); +} + + +char * +mapfile(char *file, size_t *sizep) +{ + struct stat sb; + caddr_t addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) { + perror("open(mapfile)"); + return(NULL); + } + + if (fstat(fd, &sb) == -1) { + perror("fstat(mapfile)"); + close(fd); + return(NULL); + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (addr == (caddr_t)-1) { + perror("mmap(mapfile)"); + close(fd); + return(NULL); + } + close(fd); + *sizep = sb.st_size; + return(char *)addr; +} + + +int +readconfig(char *filename) +{ + char c, buf[512], *s, *t, *errtxt = NULL, *line; + int num, err = 0; + ipnat_t *ipn; + l4cfg_t *l4; + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) { + perror("open(configfile)"); + return(-1); + } + + bzero((char *)&template, sizeof(template)); + template.l4_fd = -1; + template.l4_rw = -1; + template.l4_sin.sin_family = AF_INET; + ipn = &template.l4_nat; + ipn->in_flags = IPN_TCP|IPN_ROUNDR; + ipn->in_redir = NAT_REDIRECT; + + for (num = 1; fgets(buf, sizeof(buf), fp); num++) { + s = strchr(buf, '\n'); + if (!s) { + fprintf(stderr, "%d: line too long\n", num); + fclose(fp); + return(-1); + } + + *s = '\0'; + + /* + * lines which are comments + */ + s = strchr(buf, '#'); + if (s) + *s = '\0'; + + /* + * Skip leading whitespace + */ + for (line = buf; (c = *line) && ISSPACE(c); line++) + ; + if (!*line) + continue; + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Parsing: [%s]\n", line); + t = strtok(line, " \t"); + if (!t) + continue; + if (!strcasecmp(t, "interface")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } + + if (!strchr(t, ',')) { + fprintf(stderr, + "%d: local address,port missing\n", + num); + err = -1; + break; + } + + strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); + if (!gethostport(t, num, &ipn->in_outip, + &ipn->in_pmin)) { + errtxt = line; + err = -1; + break; + } + ipn->in_outmsk = 0xffffffff; + ipn->in_pmax = ipn->in_pmin; + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Interface %s %s/%#x port %u\n", + ipn->in_ifname, + inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ipn->in_pmin); + } else if (!strcasecmp(t, "remote")) { + if (!*ipn->in_ifname) { + fprintf(stderr, + "%d: ifname not set prior to remote\n", + num); + err = -1; + break; + } + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, ""); + if (!s || !t || strcasecmp(s, "server")) { + errtxt = line; + err = -1; + break; + } + + ipn->in_pnext = 0; + if (!gethostport(t, num, &ipn->in_inip, + &ipn->in_pnext)) { + errtxt = line; + err = -1; + break; + } + ipn->in_inmsk = 0xffffffff; + if (ipn->in_pnext == 0) + ipn->in_pnext = ipn->in_pmin; + + l4 = (l4cfg_t *)malloc(sizeof(*l4)); + if (!l4) { + fprintf(stderr, "%d: out of memory (%d)\n", + num, sizeof(*l4)); + err = -1; + break; + } + bcopy((char *)&template, (char *)l4, sizeof(*l4)); + l4->l4_sin.sin_addr = ipn->in_in[0]; + l4->l4_sin.sin_port = ipn->in_pnext; + l4->l4_next = l4list; + l4list = l4; + } else if (!strcasecmp(t, "connect")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + ctimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, "connect timeout %d\n", + ctimeout); + } else if (!strcasecmp(s, "frequency")) { + frequency = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "connect frequency %d\n", + frequency); + } else { + errtxt = line; + err = -1; + break; + } + } else if (!strcasecmp(t, "probe")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "string")) { + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + t = strtok(NULL, ""); + if (!t) { + fprintf(stderr, + "%d: No probe string\n", num); + err = -1; + break; + } + + probe = malloc(strlen(t)); + copystr(probe, t); + plen = strlen(probe); + if (opts & OPT_VERBOSE) + fprintf(stderr, "Probe string [%s]\n", + probe); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + probe = mapfile(t, &plen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Probe file %s len %u@%p\n", + t, plen, probe); + } + } else if (!strcasecmp(t, "response")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + rtimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "response timeout %d\n", + rtimeout); + } else if (!strcasecmp(s, "string")) { + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = strdup(strtok(NULL, "")); + rlen = strlen(response); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response string [%s]\n", + response); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = mapfile(t, &rlen); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response file %s len %u@%p\n", + t, rlen, response); + } + } else { + errtxt = line; + err = -1; + break; + } + } + + if (errtxt) + fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); + fclose(fp); + return(err); +} + + +void +usage(char *prog) +{ + fprintf(stderr, "Usage: %s -f <configfile>\n", prog); + exit(1); +} + + +int +main(int argc, char *argv[]) +{ + char *config = NULL; + int c; + + while ((c = getopt(argc, argv, "f:nv")) != -1) + switch (c) + { + case 'f' : + config = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (config == NULL) + usage(argv[0]); + + if (readconfig(config)) + exit(1); + + if (!l4list) { + fprintf(stderr, "No remote servers, exiting."); + exit(1); + } + + if (!(opts & OPT_DONOTHING)) { + natfd = open(IPL_NAT, O_RDWR); + if (natfd == -1) { + perror("open(IPL_NAT)"); + exit(1); + } + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Starting...\n"); + while (runconfig() == 0) + ; +} diff --git a/share/examples/ipfilter/l4check/l4check.conf b/share/examples/ipfilter/l4check/l4check.conf new file mode 100644 index 000000000000..d000e9fc5b48 --- /dev/null +++ b/share/examples/ipfilter/l4check/l4check.conf @@ -0,0 +1,31 @@ +# +# NOTE: ORDER IS IMPORTANT IN THIS FILE +# +# Interface to do the redirections on and the IP address which will be +# targeted. +# +interface nf0 192.168.1.1,2100 +# +connect timeout 1 +connect frequency 20 +# +# If no probe string is specified, a successful connection implies the +# server is still alive. +# +probe string GET /\n\n +#probe file http.check +# +response timeout 4 +response string <HTML> +#response file http.ok +# +# Here we have multiple servers, listed because that's what happens to be +# used for testing of connect timeoutes, read timeouts, success and things +# which don't connect. +# +remote server 192.168.1.2,23 +remote server 192.168.1.2,2101 +remote server 192.168.1.3,25 +remote server 192.168.1.254,8000 +remote server 192.168.1.1,9 +# diff --git a/share/examples/ipfilter/mkfilters b/share/examples/ipfilter/mkfilters new file mode 100644 index 000000000000..fe15c55563ab --- /dev/null +++ b/share/examples/ipfilter/mkfilters @@ -0,0 +1,116 @@ +#!/usr/local/bin/perl +# for best results, bring up all your interfaces before running this + +if ($^O =~ m/^irix/i) +{ + &irix_mkfilters || regular_mkfilters || die $!; +} +else +{ + ®ular_mkfilters || irix_mkfilters || die $!; +} + +foreach $i (keys %ifaces) { + $net{$i} = $inet{$i}."/".$netmask{$i} if (defined($inet{$i})); +} +# +# print out route suggestions +# +print "#\n"; +print "# The following routes should be configured, if not already:\n"; +print "#\n"; +foreach $i (keys %ifaces) { + next if (($i =~ /lo/) || !defined($net{$i}) || defined($ppp{$i})); + print "# route add $inet{$i} localhost 0\n"; +} +print "#\n"; + +# +# print out some generic filters which people should use somewhere near the top +# +print "block in log quick from any to any with ipopts\n"; +print "block in log quick proto tcp from any to any with short\n"; + +$grpi = 0; + +foreach $i (keys %ifaces) { + if (!defined($inet{$i})) { + next; + } + + $grpi += 100; + $grpo = $grpi + 50; + + if ($i !~ /lo/) { + print "pass out on $i all head $grpo\n"; + print "block out from 127.0.0.0/8 to any group $grpo\n"; + print "block out from any to 127.0.0.0/8 group $grpo\n"; + print "block out from any to $inet{$i}/32 group $grpo\n"; + print "pass in on $i all head $grpi\n"; + print "block in from 127.0.0.0/8 to any group $grpi\n"; + print "block in from $inet{$i}/32 to any group $grpi\n"; + foreach $j (keys %ifaces) { + if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) { + print "block in from $net{$j} to any group $grpi\n"; + } + } + } +} + +sub irix_mkfilters +{ + open(NETSTAT, "/usr/etc/netstat -i|") || return 0; + + while (defined($line = <NETSTAT>)) + { + if ($line =~ m/^Name/) + { + next; + } + elsif ($line =~ m/^(\S+)/) + { + open(I, "/usr/etc/ifconfig $1|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + } + } + close NETSTAT; # again, being neat... - Allen + return 1; +} + +sub regular_mkfilters +{ + open(I, "ifconfig -a|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + return 1; +} + +sub scan_ifconfig +{ + while (<I>) { + chop; + if (/^[a-zA-Z]+\d+:/) { + ($iface = $_) =~ s/^([a-zA-Z]+\d+).*/$1/; + $ifaces{$iface} = $iface; + next; + } + if (/inet/) { + if (/\-\-\>/) { # PPP, (SLIP?) + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$1/; + ($ppp{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$2/; + } else { + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+).*/$1/; + } + } + if (/netmask/) { + ($mask = $_) =~ s/.*netmask ([^ ]+).*/$1/; + $mask =~ s/^/0x/ if ($mask =~ /^[0-9a-f]*$/); + $netmask{$iface} = $mask; + } + if (/broadcast/) { + ($bcast{$iface} = $_) =~ s/.*broadcast ([^ ]+).*/$1/; + } + } +} + diff --git a/share/examples/ipfilter/mkfilters.1 b/share/examples/ipfilter/mkfilters.1 new file mode 100644 index 000000000000..65afaec4019e --- /dev/null +++ b/share/examples/ipfilter/mkfilters.1 @@ -0,0 +1,15 @@ +.\" +.TH MKFILTERS 1 +.SH NAME +mkfilters \- generate a minimal firewall ruleset for ipfilter +.SH SYNOPSIS +.B mkfilters +.SH FILES +/usr/share/examples/ipfilter/mkfilters +.SH DESCRIPTION +.PP +\fBmkfilters\fP is a perl script that generates a minimal filter rule set for +use with \fBipfilter\fP by parsing the output of \fBifconfig\fP. +.DT +.SH SEE ALSO +ipf(8), ipf(5), ipfilter(5), ifconfig(8) diff --git a/share/examples/ipfilter/mlfk_rule.c b/share/examples/ipfilter/mlfk_rule.c new file mode 100644 index 000000000000..9126e4d97281 --- /dev/null +++ b/share/examples/ipfilter/mlfk_rule.c @@ -0,0 +1,69 @@ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> + +#include <netinet/ipl.h> +#include <netinet/ip_compat.h> +#include <netinet/ip_fil.h> +#include <netinet/ip_state.h> +#include <netinet/ip_nat.h> +#include <netinet/ip_auth.h> +#include <netinet/ip_frag.h> + +#include "ip_rules.h" + +extern ipf_main_softc_t ipfmain; + +static int +ipfrule_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) + { + case MOD_LOAD : + error = ipfrule_add(); + if (!error) + ipfmain.ipf_refcnt++; + break; + case MOD_UNLOAD : + error = ipfrule_remove(); + if (!error) + ipfmain.ipf_refcnt--; + break; + default: + error = EINVAL; + break; + } + return(error); +} + +static moduledata_t ipfrulemod = { + "ipfrule", + ipfrule_modevent, + 0 +}; +DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_DEPEND +MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1); +#endif +#ifdef MODULE_VERSION +MODULE_VERSION(ipfrule, 1); +#endif diff --git a/share/examples/ipfilter/rules.txt b/share/examples/ipfilter/rules.txt new file mode 100644 index 000000000000..f8ceb8a4352c --- /dev/null +++ b/share/examples/ipfilter/rules.txt @@ -0,0 +1,181 @@ +# +# block all incoming TCP packets on le0 from host "foo" to any destination. +# +block in on le0 proto tcp from foo/32 to any + + ------------------------------------------------------------------------ + +# +# block all outgoing TCP packets on le0 from any host to port 23 of host bar. +# +block out on le0 proto tcp from any to bar/32 port != 23 + + ------------------------------------------------------------------------ + +# +# block all inbound packets. +# +block in from any to any +# +# pass through packets to and from localhost. +# +pass in from 127.0.0.1/32 to 127.0.0.1/32 +# +# allow a variety of individual hosts to send any type of IP packet to any +# other host. +# +pass in from 10.1.3.1 to any +pass in from 10.1.3.2 to any +pass in from 10.1.3.3 to any +pass in from 10.1.3.4 to any +pass in from 10.1.3.5 to any +pass in from 10.1.0.13/32 to any +pass in from 10.1.1.1/32 to any +pass in from 10.1.2.1/32 to any +# +# +# block all outbound packets. +# +block out from any to any +# +# allow any packets destined for localhost out. +# +pass out from any to 127.0.0.1/32 +# +# allow any host to send any IP packet out to a limited number of hosts. +# +pass out from any to 10.1.3.1/32 +pass out from any to 10.1.3.2/32 +pass out from any to 10.1.3.3/32 +pass out from any to 10.1.3.4/32 +pass out from any to 10.1.3.5/32 +pass out from any to 10.1.0.13/32 +pass out from any to 10.1.1.1/32 +pass out from any to 10.1.2.1/32 + + ------------------------------------------------------------------------ + +# +# block all ICMP packets. +# +block in proto icmp from any to any + + ------------------------------------------------------------------------ + +# +# test ruleset +# +# allow packets coming from foo to bar through. +# +pass from foo to bar +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass proto tcp from fubar/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass proto udp from fubar port != 53 to localhost +# +# block all ICMP unreachables. +# +block from any to any icmp unreach +# +# allow packets through which have a non-standard IP header length (ie there +# are IP options such as source-routing present). +# +pass from any to any with ipopts + + ------------------------------------------------------------------------ + +# +# block all TCP packets with only the SYN flag set (this is the first +# packet sent to establish a connection). +# +block in proto tcp from any to any flags S/SA + + ------------------------------------------------------------------------ + +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 +# +# Log all short TCP packets to qe3, with "packetlog" as the intended +# destination for the packet. +# +block in to qe3:packetlog proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in dup-to le0:packetlog proto tcp all flags S/SA +# +# Route all UDP packets through transparently. +# +pass in fastroute proto udp all +# +# Route all ICMP packets to network 10 out through le1, to "router" +# +pass in to le1:router proto icmp all + + ------------------------------------------------------------------------ +Return to the IP Filter home page diff --git a/share/examples/ipfilter/rules/BASIC.NAT b/share/examples/ipfilter/rules/BASIC.NAT new file mode 100644 index 000000000000..213e33815c19 --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC.NAT @@ -0,0 +1,46 @@ +#!/sbin/ipnat -f - +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# If we have only 1 valid IP address from our ISP, then we do this: +# +# To make ftp work, using the internal ftp proxy, use: +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp +# +# For normal TCP/UDP and other IP protocols +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000 +map ppp0 w.x.y.z/24 -> a.b.c.d/32 +# +# if we get a different dialup IP address each time, then we would use: +# +#map ppp0 w.x.y.z/24 -> 0/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> 0/32 +# +# If we have a class C address space of valid IP#'s from our ISP, then we can +# do this: +# +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 +# +# or, if we only have a small number of PC's, this: +# +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 diff --git a/share/examples/ipfilter/rules/BASIC_1.FW b/share/examples/ipfilter/rules/BASIC_1.FW new file mode 100644 index 000000000000..642dde061efd --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC_1.FW @@ -0,0 +1,99 @@ +#!/sbin/ipf -f - +# +# SAMPLE: RESTRICTIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block in log proto tcp all flags S/SA head 101 group 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block in log proto tcp all flags S/SA head 201 group 200 +block in log proto udp all head 202 group 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Allow outgoing DNS requests (no named on firewall) +# +pass in quick proto udp from any to any port = 53 keep state group 202 +# +# If we were running named on the firewall and all internal hosts talked to +# it, we'd use the following: +# +#pass in quick proto udp from any to w.x.y.z/32 port = 53 keep state group 202 +#pass out quick on ppp0 proto udp from a.b.c.d/32 to any port = 53 keep state +# +# Allow outgoing FTP from any internal host to any external FTP server. +# +pass in quick proto tcp from any to any port = ftp keep state group 201 +pass in quick proto tcp from any to any port = ftp-data keep state group 201 +pass in quick proto tcp from any port = ftp-data to any port > 1023 keep state group 101 +# +# Allow NTP from any internal host to any external NTP server. +# +pass in quick proto udp from any to any port = ntp keep state group 202 +# +# Allow outgoing connections: SSH, TELNET, WWW +# +pass in quick proto tcp from any to any port = 22 keep state group 201 +pass in quick proto tcp from any to any port = telnet keep state group 201 +pass in quick proto tcp from any to any port = www keep state group 201 +# +#------------------------------------------------------- +block in log proto tcp from any to a.b.c.d/32 flags S/SA head 110 group 100 +# +# Allow incoming to the external firewall interface: mail, WWW, DNS +# +pass in log quick proto tcp from any to any port = smtp keep state group 110 +pass in log quick proto tcp from any to any port = www keep state group 110 +pass in log quick proto tcp from any to any port = 53 keep state group 110 +pass in log quick proto udp from any to any port = 53 keep state group 100 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/share/examples/ipfilter/rules/BASIC_2.FW b/share/examples/ipfilter/rules/BASIC_2.FW new file mode 100644 index 000000000000..1d4fd7317673 --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC_2.FW @@ -0,0 +1,72 @@ +#!/sbin/ipf -f - +# +# SAMPLE: PERMISSIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Allow any communication between the inside network and the outside only. +# +# Allow all outgoing connections (SSH, TELNET, FTP, WWW, gopher, etc) +# +pass in log quick proto tcp all flags S/SA keep state group 200 +# +# Support all UDP `connections' initiated from inside. +# +# Allow ping out +# +pass in log quick proto icmp all keep state group 200 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/share/examples/ipfilter/rules/example.1 b/share/examples/ipfilter/rules/example.1 new file mode 100644 index 000000000000..ff93f492cafe --- /dev/null +++ b/share/examples/ipfilter/rules/example.1 @@ -0,0 +1,4 @@ +# +# block all incoming TCP packets on le0 from host 10.1.1.1 to any destination. +# +block in on le0 proto tcp from 10.1.1.1/32 to any diff --git a/share/examples/ipfilter/rules/example.10 b/share/examples/ipfilter/rules/example.10 new file mode 100644 index 000000000000..560d1e670f61 --- /dev/null +++ b/share/examples/ipfilter/rules/example.10 @@ -0,0 +1,12 @@ +# +# pass ack packets (ie established connection) +# +pass in proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +pass out proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +# +# block incoming connection requests to my internal network from the big bad +# internet. +# +block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA +# to block the replies: +block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA diff --git a/share/examples/ipfilter/rules/example.11 b/share/examples/ipfilter/rules/example.11 new file mode 100644 index 000000000000..c6b4e7ff0d73 --- /dev/null +++ b/share/examples/ipfilter/rules/example.11 @@ -0,0 +1,26 @@ +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block anything trying to get to X terminal ports, X:0 to X:9 +# +block in proto tcp from any to any port 5999 >< 6010 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +block in proto tcp/udp all +pass in proto tcp/udp from any to any port 512 <> 515 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +pass in proto tcp/udp all +block in proto tcp/udp from any to any port 511 >< 516 diff --git a/share/examples/ipfilter/rules/example.12 b/share/examples/ipfilter/rules/example.12 new file mode 100644 index 000000000000..c0ba1d3cdda1 --- /dev/null +++ b/share/examples/ipfilter/rules/example.12 @@ -0,0 +1,17 @@ +# +# get rid of all short IP fragments (too small for valid comparison) +# +block in proto tcp all with short +# +# drop and log any IP packets with options set in them. +# +block in log all with ipopts +# +# log packets with BOTH ssrr and lsrr set +# +log in all with opt lsrr,ssrr +# +# drop any source routing options +# +block in quick all with opt lsrr +block in quick all with opt ssrr diff --git a/share/examples/ipfilter/rules/example.13 b/share/examples/ipfilter/rules/example.13 new file mode 100644 index 000000000000..854f07f1694f --- /dev/null +++ b/share/examples/ipfilter/rules/example.13 @@ -0,0 +1,17 @@ +# +# Log all short TCP packets to qe3, with 10.3.3.3 as the intended +# destination for the packet. +# +block in on qe0 to qe3:10.3.3.3 proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in on le0 dup-to le1:10.3.3.3 proto tcp all flags S/SA +# +# Route all UDP packets through transparently. +# +pass in on ppp0 fastroute proto udp all +# +# Route all ICMP packets to network 10 out through le1, to 10.3.3.1 +# +pass in on le0 to le1:10.3.3.1 proto icmp all diff --git a/share/examples/ipfilter/rules/example.2 b/share/examples/ipfilter/rules/example.2 new file mode 100644 index 000000000000..4f81725eeb0c --- /dev/null +++ b/share/examples/ipfilter/rules/example.2 @@ -0,0 +1,5 @@ +# +# block all outgoing TCP packets on le0 from any host to port 23 of +# host 10.1.1.2 +# +block out on le0 proto tcp from any to 10.1.1.3/32 port = 23 diff --git a/share/examples/ipfilter/rules/example.3 b/share/examples/ipfilter/rules/example.3 new file mode 100644 index 000000000000..cd31f73e7c2b --- /dev/null +++ b/share/examples/ipfilter/rules/example.3 @@ -0,0 +1,40 @@ +# +# block all inbound packets. +# +block in from any to any +# +# pass through packets to and from localhost. +# +pass in from 127.0.0.1/32 to 127.0.0.1/32 +# +# allow a variety of individual hosts to send any type of IP packet to any +# other host. +# +pass in from 10.1.3.1/32 to any +pass in from 10.1.3.2/32 to any +pass in from 10.1.3.3/32 to any +pass in from 10.1.3.4/32 to any +pass in from 10.1.3.5/32 to any +pass in from 10.1.0.13/32 to any +pass in from 10.1.1.1/32 to any +pass in from 10.1.2.1/32 to any +# +# +# block all outbound packets. +# +block out from any to any +# +# allow any packets destined for localhost out. +# +pass out from any to 127.0.0.1/32 +# +# allow any host to send any IP packet out to a limited number of hosts. +# +pass out from any to 10.1.3.1/32 +pass out from any to 10.1.3.2/32 +pass out from any to 10.1.3.3/32 +pass out from any to 10.1.3.4/32 +pass out from any to 10.1.3.5/32 +pass out from any to 10.1.0.13/32 +pass out from any to 10.1.1.1/32 +pass out from any to 10.1.2.1/32 diff --git a/share/examples/ipfilter/rules/example.4 b/share/examples/ipfilter/rules/example.4 new file mode 100644 index 000000000000..7918ec2fbd99 --- /dev/null +++ b/share/examples/ipfilter/rules/example.4 @@ -0,0 +1,4 @@ +# +# block all ICMP packets. +# +block in proto icmp from any to any diff --git a/share/examples/ipfilter/rules/example.5 b/share/examples/ipfilter/rules/example.5 new file mode 100644 index 000000000000..6d688b5eab80 --- /dev/null +++ b/share/examples/ipfilter/rules/example.5 @@ -0,0 +1,25 @@ +# +# test ruleset +# +# allow packets coming from foo to bar through. +# +pass in from 10.1.1.2 to 10.2.1.1 +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block all ICMP unreachables. +# +block in proto icmp from any to any icmp-type unreach +# +# allow packets through which have a non-standard IP header length (ie there +# are IP options such as source-routing present). +# +pass in from any to any with ipopts diff --git a/share/examples/ipfilter/rules/example.6 b/share/examples/ipfilter/rules/example.6 new file mode 100644 index 000000000000..d40f0f3d2a18 --- /dev/null +++ b/share/examples/ipfilter/rules/example.6 @@ -0,0 +1,5 @@ +# +# block all TCP packets with only the SYN flag set (this is the first +# packet sent to establish a connection) out of the SYN-ACK pair. +# +block in proto tcp from any to any flags S/SA diff --git a/share/examples/ipfilter/rules/example.7 b/share/examples/ipfilter/rules/example.7 new file mode 100644 index 000000000000..062de9811935 --- /dev/null +++ b/share/examples/ipfilter/rules/example.7 @@ -0,0 +1,12 @@ +# block all ICMP packets. +# +block in proto icmp all +# +# allow in ICMP echos and echo-replies. +# +pass in on le1 proto icmp from any to any icmp-type echo +pass in on le1 proto icmp from any to any icmp-type echorep +# +# block all ICMP destination unreachable packets which are port-unreachables +# +block in on le1 proto icmp from any to any icmp-type unreach code 3 diff --git a/share/examples/ipfilter/rules/example.8 b/share/examples/ipfilter/rules/example.8 new file mode 100644 index 000000000000..baa02581256e --- /dev/null +++ b/share/examples/ipfilter/rules/example.8 @@ -0,0 +1,10 @@ +# +# block all incoming TCP connections but send back a TCP-RST for ones to +# the ident port +# +block in proto tcp from any to any flags S/SA +block return-rst in quick proto tcp from any to any port = 113 flags S/SA +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp in proto udp from any to any diff --git a/share/examples/ipfilter/rules/example.9 b/share/examples/ipfilter/rules/example.9 new file mode 100644 index 000000000000..daff2031db8e --- /dev/null +++ b/share/examples/ipfilter/rules/example.9 @@ -0,0 +1,12 @@ +# +# drop all packets without IP security options +# +block in all +pass in all with opt sec +# +# only allow packets in and out on le1 which are top secret +# +block out on le1 all +pass out on le1 all with opt sec-class topsecret +block in on le1 all +pass in on le1 all with opt sec-class topsecret diff --git a/share/examples/ipfilter/rules/example.sr b/share/examples/ipfilter/rules/example.sr new file mode 100644 index 000000000000..c4c1994030ba --- /dev/null +++ b/share/examples/ipfilter/rules/example.sr @@ -0,0 +1,61 @@ +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 diff --git a/share/examples/ipfilter/rules/firewall b/share/examples/ipfilter/rules/firewall new file mode 100644 index 000000000000..f26b7150b98c --- /dev/null +++ b/share/examples/ipfilter/rules/firewall @@ -0,0 +1,39 @@ +Configuring IP Filter for firewall usage. +========================================= + +Step 1 - Block out "bad" IP packets. +------------------------------------ + +Run the perl script "mkfilters". This will generate a list of blocking +rules which: + a) blocks all packets which might belong to an IP Spoofing attack; + b) blocks all packets with IP options; + c) blocks all packets which have a length which is too short for + any legal packet; + +Step 2 - Convert Network Security Policy to filter rules. +--------------------------------------------------------- + +Draw up a list of which services you want to allow users to use on the +Internet (e.g. WWW, ftp, etc). Draw up a separate list for what you +want each host that is part of your firewall to be allowed to do, including +communication with internal hosts. + +Step 3 - Create TCP "keep state" rules. +--------------------------------------- + +For each service that uses TCP, create a rule as follows: + +pass in on <int-a> proto tcp from <int-net> to any port <ext-service> flags S/SA keep state + +where +* "int-a" is the internal interface of the firewall. That is, it is the + closest to your internal network in terms of network hops. + +* "int-net" is the internal network IP# subnet address range. This might + be something like 10.1.0.0/16, or 128.33.1.0/24 + +* "ext-service" is the service to which you wish to connect or if it doesn't + have a proper name, a number can be used. The translation of "ext-service" + as a name to a number is controlled with the /etc/services file. + diff --git a/share/examples/ipfilter/rules/ftp-proxy b/share/examples/ipfilter/rules/ftp-proxy new file mode 100644 index 000000000000..ad2f7171e85a --- /dev/null +++ b/share/examples/ipfilter/rules/ftp-proxy @@ -0,0 +1,45 @@ +How to setup FTP proxying using the built in proxy code. +======================================================== + +NOTE: Currently, the built-in FTP proxy is only available for use with NAT + (i.e. only if you're already using "map" rules with ipnat). It does + support null-NAT mappings, that is, using the proxy without changing + the addresses. + +Lets assume your network diagram looks something like this: + + +[host A] + |a +---+-------------+---------- + |b + [host B] + |c +---+-------------+---------- + |d +[host C] + +and IP Filter is running on host B. If you want to proxy FTP from A to C +then you would do: + +map int-c ipaddr-a/32 -> ip-addr-c-net/32 proxy port ftp ftp/tcp + +int-c = name of "interface c" +ipaddr-a = ip# of interface a +ipaddr-c-net = another ip# on the C-network (usually not the same as the +interface). + +e.g., if host A was 10.1.1.1, host B had two network interfaces ed0 and vx0 +which had IP#'s 10.1.1.2 and 203.45.67.89 respectively, and host C was +203.45.67.90, you would do: + +map vx0 10.1.1.1/32 -> 203.45.67.91/32 proxy port ftp ftp/tcp + +where: +ipaddr-a = 10.1.1.1 +int-c = vx0 +ipaddr-c-net = 203.45.67.91 + +The "map" rule for this proxy should precede any other NAT rules you are +using. + diff --git a/share/examples/ipfilter/rules/ftppxy b/share/examples/ipfilter/rules/ftppxy new file mode 100755 index 000000000000..2c42c527fa1e --- /dev/null +++ b/share/examples/ipfilter/rules/ftppxy @@ -0,0 +1,6 @@ +#!/bin/sh +# The proxy bit is as follows: +# proxy [port <portname>] <tag>/<protocol> +# the <tag> should match a tagname in the proxy table, as does the protocol. +# this format isn't finalised yet +echo "map ed0 0/0 -> 192.1.1.1/32 proxy port ftp ftp/tcp" | /sbin/ipnat -f - diff --git a/share/examples/ipfilter/rules/ip_rules b/share/examples/ipfilter/rules/ip_rules new file mode 100644 index 000000000000..9850f16b9306 --- /dev/null +++ b/share/examples/ipfilter/rules/ip_rules @@ -0,0 +1,3 @@ +# Used to generate ../ip_rules.c and ../ip_rules.h +pass in all +pass out all diff --git a/share/examples/ipfilter/rules/ipmon.conf b/share/examples/ipfilter/rules/ipmon.conf new file mode 100644 index 000000000000..652afceb3ea1 --- /dev/null +++ b/share/examples/ipfilter/rules/ipmon.conf @@ -0,0 +1,25 @@ +# +# +# +# +match { logtag = 10000; } +do { execute("/usr/bin/mail -s 'logtag 10000' root"); }; +# +match { logtag = 2000, every 10 seconds; } +do { execute("echo 'XXXXXXXX tag 2000 packet XXXXXXXX'"); }; +# +match { protocol = udp, result = block; } +do { file("file:///var/log/udp-block"); }; +# +match { protocol = tcp, result = block, dstport = 25; } +do { syslog("local0.info"), syslog("local1."), syslog(".warn"); }; +# +match { srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { execute("/usr/bin/mail -s 'from 10.1 to 192.168.1' root"); }; + +# +match { + rule = 12, logtag = 101, direction = in, result = block, + protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { nothing; }; +# diff --git a/share/examples/ipfilter/rules/nat-setup b/share/examples/ipfilter/rules/nat-setup new file mode 100644 index 000000000000..b10e8f113e0c --- /dev/null +++ b/share/examples/ipfilter/rules/nat-setup @@ -0,0 +1,77 @@ +Configuring NAT on your network. +================================ + +To start setting up NAT, we need to define which is your "internal" interface +and which is your "external" interface. The "internal" interface is the +network adapter connected to the network with private IP addresses which +you need to change for communicating on the Internet. The "external" +interface is configured with a valid internet address. + +For example, your internal interface might have an IP# of 10.1.1.1 and be +connected to your ethernet, whilst your external interface might be a PPP +connection with an IP number of 204.51.62.176. + +Thus your network might look like this: + +<Internal Network> + [pc] [pc] + | | ++-+---------+------+ + | + [firewall] + | + | + Internet +<External Network> + + +Writing the map-rule. +--------------------- +When you're connected to the Internet, you will either have a block of IP +addresses assigned to you, maybe several different blocks, or you use a +single IP address, i.e. with dialup PPP. If you have a block of addresses +assigned, these can be used to create either a 1:1 mapping (if you have +only a few internal IP addresses) or N:1 mappings, where groups of internal +addresses map to a single IP address and unless you have enough Internet +addresses for a 1:1 mapping, you will want to do "portmapping" for TCP and +UDP port numbers. + +For an N:1 situation, you might have: + +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap + +where if you had 16 addresses available, you could do: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap + +Or if you wanted to allocate subnets to each IP#, you might do: + +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap + +*** NOTE: NAT rules are used on a first-match basis only! + + +Filtering with NAT. +------------------- +IP Filter will always translate addresses in a packet _BEFORE_ it checks its +access list for inbound packets and translates addresses _AFTER_ it has +checked the access control lists for outbound packets. + +For example (using the above NAT rules), if you wanted to prevent all hosts +in the 10.1.2.0/24 subnet from using NAT, you might use the following rule +with ipf: + +block out on ppp0 from 10.1.2.0/24 to any +block in on ppp0 from any to 10.1.2.0/24 + +and use these with ipnat: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap diff --git a/share/examples/ipfilter/rules/nat.eg b/share/examples/ipfilter/rules/nat.eg new file mode 100644 index 000000000000..9c26754a57fa --- /dev/null +++ b/share/examples/ipfilter/rules/nat.eg @@ -0,0 +1,14 @@ +# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source +# port number to something between 10,000 and 20,000 inclusive. For all other +# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily +# for each new user. +# +map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000 +map ed1 10.1.0.0/16 -> 240.1.0.0/24 +# +# Redirection is triggered for input packets. +# For example, to redirect FTP connections through this box, to the local ftp +# port, forcing them to connect through a proxy, you would use: +# +rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp +# diff --git a/share/examples/ipfilter/rules/pool.conf b/share/examples/ipfilter/rules/pool.conf new file mode 100644 index 000000000000..285398ddf3b1 --- /dev/null +++ b/share/examples/ipfilter/rules/pool.conf @@ -0,0 +1,4 @@ +# +pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255, + 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255, + 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 }; diff --git a/share/examples/ipfilter/rules/server b/share/examples/ipfilter/rules/server new file mode 100644 index 000000000000..de0e9bbd06d8 --- /dev/null +++ b/share/examples/ipfilter/rules/server @@ -0,0 +1,11 @@ +# +# For a network server, which has two interfaces, 128.1.40.1 (le0) and +# 128.1.2.1 (le1), we want to block all IP spoofing attacks. le1 is +# connected to the majority of the network, whilst le0 is connected to a +# leaf subnet. We're not concerned about filtering individual services +# or +# +pass in quick on le0 from 128.1.40.0/24 to any +block in log quick on le0 from any to any +block in log quick on le1 from 128.1.1.0/24 to any +pass in quick on le1 from any to any diff --git a/share/examples/ipfilter/rules/tcpstate b/share/examples/ipfilter/rules/tcpstate new file mode 100644 index 000000000000..339a25f963fc --- /dev/null +++ b/share/examples/ipfilter/rules/tcpstate @@ -0,0 +1,13 @@ +# +# Only allow TCP packets in/out of le0 if there is an outgoing connection setup +# somewhere, waiting for it. +# +pass out quick on le0 proto tcp from any to any flags S/SAFR keep state +block out on le0 proto tcp all +block in on le0 proto tcp all +# +# allow nameserver queries and replies to pass through, but no other UDP +# +pass out quick on le0 proto udp from any to any port = 53 keep state +block out on le0 proto udp all +block in on le0 proto udp all diff --git a/share/examples/ipfilter/samples/Makefile b/share/examples/ipfilter/samples/Makefile new file mode 100644 index 000000000000..47ab4a26d5c0 --- /dev/null +++ b/share/examples/ipfilter/samples/Makefile @@ -0,0 +1,24 @@ +CC=gcc +all: + @echo "Please do one of the following:" + @echo "make bsd" + @echo "make bsdi" + @echo "make freebsd" + @echo "make freebsd22" + @echo "make netbsd" + @echo "make openbsd" + @echo "make sunos4" + @echo "make sunos5" + +sunos5: + $(CC) -I.. userauth.c -o userauth -lsocket -lnsl + $(CC) -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. relay.c -o relay -lsocket -lnsl + +freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd: + $(CC) -I.. userauth.c -o userauth + $(CC) -I.. proxy.c -o proxy + $(CC) -I.. relay.c -o relay + +clean: + /bin/rm -f userauth proxy relay diff --git a/share/examples/ipfilter/samples/ipfilter-pb.gif b/share/examples/ipfilter/samples/ipfilter-pb.gif Binary files differnew file mode 100644 index 000000000000..afaefa866541 --- /dev/null +++ b/share/examples/ipfilter/samples/ipfilter-pb.gif diff --git a/share/examples/ipfilter/samples/proxy.c b/share/examples/ipfilter/samples/proxy.c new file mode 100644 index 000000000000..7f5949b519be --- /dev/null +++ b/share/examples/ipfilter/samples/proxy.c @@ -0,0 +1,316 @@ + +/* + * Sample transparent proxy program. + * + * Sample implementation of a program which intercepts a TCP connectiona and + * just echos all data back to the origin. Written to work via inetd as a + * "nonwait" program running as root; ie. + * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy + * with a NAT rue like this: + * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1 + */ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <syslog.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <sys/ioccom.h> +# include <sys/sysmacros.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin, sloc, sout; + ipfobj_t obj; + natlookup_t natlook; + char buffer[512]; + int namelen, fd, n; + + /* + * get IP# and port # of the remote end of the connection (at the + * origin). + */ + namelen = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) { + perror("getpeername"); + exit(-1); + } + + /* + * get IP# and port # of the local end of the connection (at the + * man-in-the-middle). + */ + namelen = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) { + perror("getsockname"); + exit(-1); + } + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(natlook); + obj.ipfo_ptr = &natlook; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + /* + * Build up the NAT natlookup structure. + */ + bzero((char *)&natlook, sizeof(natlook)); + natlook.nl_outip = sin.sin_addr; + natlook.nl_inip = sloc.sin_addr; + natlook.nl_flags = IPN_TCP; + natlook.nl_outport = sin.sin_port; + natlook.nl_inport = sloc.sin_port; + + /* + * Open the NAT device and lookup the mapping pair. + */ + fd = open(IPNAT_NAME, O_RDONLY); + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + perror("ioctl(SIOCGNATL)"); + exit(-1); + } + +#define DO_NAT_OUT +#ifdef DO_NAT_OUT + if (argc > 1) + do_nat_out(0, 1, fd, &natlook, argv[1]); +#else + + /* + * Log it + */ + syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + printf("connect to %s,%d\n", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + + /* + * Just echo data read in from stdin to stdout + */ + while ((n = read(0, buffer, sizeof(buffer))) > 0) + if (write(1, buffer, n) != n) + break; + close(0); +#endif +} + + +#ifdef DO_NAT_OUT +do_nat_out(in, out, fd, nlp, extif) + int fd; + natlookup_t *nlp; + char *extif; +{ + nat_save_t ns, *nsp = &ns; + struct sockaddr_in usin; + u_32_t sum1, sum2, sumd; + int onoff, ofd, slen; + ipfobj_t obj; + ipnat_t *ipn; + nat_t *nat; + + bzero((char *)&ns, sizeof(ns)); + + nat = &ns.ipn_nat; + nat->nat_p = IPPROTO_TCP; + nat->nat_dir = NAT_OUTBOUND; + if ((extif != NULL) && (*extif != '\0')) { + strncpy(nat->nat_ifnames[0], extif, + sizeof(nat->nat_ifnames[0])); + strncpy(nat->nat_ifnames[1], extif, + sizeof(nat->nat_ifnames[1])); + nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; + nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; + } + + ofd = socket(AF_INET, SOCK_DGRAM, 0); + bzero((char *)&usin, sizeof(usin)); + usin.sin_family = AF_INET; + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; + (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin)); + slen = sizeof(usin); + (void) getsockname(ofd, (struct sockaddr *)&usin, &slen); + close(ofd); +printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr)); + + if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + perror("socket"); + usin.sin_port = 0; + if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("bind"); + slen = sizeof(usin); + if (getsockname(ofd, (struct sockaddr *)&usin, &slen)) + perror("getsockname"); +printf("local port# to use: %d\n", ntohs(usin.sin_port)); + + nat->nat_inip = usin.sin_addr; + nat->nat_outip = nlp->nl_outip; + nat->nat_oip = nlp->nl_realip; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); + + nat->nat_inport = usin.sin_port; + nat->nat_outport = nlp->nl_outport; + nat->nat_oport = nlp->nl_realport; + + nat->nat_flags = IPN_TCPUDP; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_ptr = nsp; + obj.ipfo_type = IPFOBJ_NATSAVE; + + onoff = 1; + if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { + if (ioctl(fd, SIOCSTPUT, &obj) != 0) + perror("SIOCSTPUT"); + onoff = 0; + if (ioctl(fd, SIOCSTLCK, &onoff) != 0) + perror("SIOCSTLCK"); + } + + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; +printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr), +ntohs(usin.sin_port)); +fflush(stdout); + if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("connect"); + + relay(in, out, ofd); +} + + +relay(in, out, net) + int in, out, net; +{ + char netbuf[1024], outbuf[1024]; + char *nwptr, *nrptr, *owptr, *orptr; + size_t nsz, osz; + fd_set rd, wr; + int i, n, maxfd; + + n = 0; + maxfd = in; + if (out > maxfd) + maxfd = out; + if (net > maxfd) + maxfd = net; + + nrptr = netbuf; + nwptr = netbuf; + nsz = sizeof(netbuf); + orptr = outbuf; + owptr = outbuf; + osz = sizeof(outbuf); + + while (n >= 0) { + FD_ZERO(&rd); + FD_ZERO(&wr); + + if (nrptr - netbuf < sizeof(netbuf)) + FD_SET(in, &rd); + if (orptr - outbuf < sizeof(outbuf)) + FD_SET(net, &rd); + + if (nsz < sizeof(netbuf)) + FD_SET(net, &wr); + if (osz < sizeof(outbuf)) + FD_SET(out, &wr); + + n = select(maxfd + 1, &rd, &wr, NULL, NULL); + + if ((n > 0) && FD_ISSET(in, &rd)) { + i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf)); + if (i <= 0) + break; + nsz -= i; + nrptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &rd)) { + i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf)); + if (i <= 0) + break; + osz -= i; + orptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(out, &wr)) { + i = write(out, owptr, orptr - owptr); + if (i <= 0) + break; + osz += i; + if (osz == sizeof(outbuf) || owptr == orptr) { + orptr = outbuf; + owptr = outbuf; + } else + owptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &wr)) { + i = write(net, nwptr, nrptr - nwptr); + if (i <= 0) + break; + nsz += i; + if (nsz == sizeof(netbuf) || nwptr == nrptr) { + nrptr = netbuf; + nwptr = netbuf; + } else + nwptr += i; + } + } + + close(net); + close(out); + close(in); +} +#endif diff --git a/share/examples/ipfilter/samples/relay.c b/share/examples/ipfilter/samples/relay.c new file mode 100644 index 000000000000..88d5fd968805 --- /dev/null +++ b/share/examples/ipfilter/samples/relay.c @@ -0,0 +1,195 @@ + +/* + * Sample program to be used as a transparent proxy. + * + * Must be executed with permission enough to do an ioctl on /dev/ipl + * or equivalent. This is just a sample and is only alpha quality. + * - Darren Reed (8 April 1996) + */ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + +#define RELAY_BUFSZ 8192 + +char ibuff[RELAY_BUFSZ]; +char obuff[RELAY_BUFSZ]; + +int relay(ifd, ofd, rfd) + int ifd, ofd, rfd; +{ + fd_set rfds, wfds; + char *irh, *irt, *rrh, *rrt; + char *iwh, *iwt, *rwh, *rwt; + int nfd, n, rw; + + irh = irt = ibuff; + iwh = iwt = obuff; + nfd = ifd; + if (nfd < ofd) + nfd = ofd; + if (nfd < rfd) + nfd = rfd; + + while (1) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if (irh > irt) + FD_SET(rfd, &wfds); + if (irh < (ibuff + RELAY_BUFSZ)) + FD_SET(ifd, &rfds); + if (iwh > iwt) + FD_SET(ofd, &wfds); + if (iwh < (obuff + RELAY_BUFSZ)) + FD_SET(rfd, &rfds); + + switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) + { + case -1 : + case 0 : + return(-1); + default : + if (FD_ISSET(ifd, &rfds)) { + rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); + if (rw == -1) + return(-1); + if (rw == 0) + return(0); + irh += rw; + n--; + } + if (n && FD_ISSET(ofd, &wfds)) { + rw = write(ofd, iwt, iwh - iwt); + if (rw == -1) + return(-1); + iwt += rw; + n--; + } + if (n && FD_ISSET(rfd, &rfds)) { + rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); + if (rw == -1) + return(-1); + if (rw == 0) + return(0); + iwh += rw; + n--; + } + if (n && FD_ISSET(rfd, &wfds)) { + rw = write(rfd, irt, irh - irt); + if (rw == -1) + return(-1); + irt += rw; + n--; + } + if (irh == irt) + irh = irt = ibuff; + if (iwh == iwt) + iwh = iwt = obuff; + } + } +} + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + ipfobj_t obj; + natlookup_t nl; + natlookup_t *nlp = &nl; + int fd, sl = sizeof(sl), se; + + openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); + if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) { + se = errno; + perror("open"); + errno = se; + syslog(LOG_ERR, "open: %m\n"); + exit(-1); + } + + bzero(&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(nl); + obj.ipfo_ptr = &nl; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + bzero(&nl, sizeof(nl)); + nl.nl_flags = IPN_TCP; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getsockname"); + errno = se; + syslog(LOG_ERR, "getsockname: %m\n"); + exit(-1); + } else { + nl.nl_inip.s_addr = sin.sin_addr.s_addr; + nl.nl_inport = sin.sin_port; + } + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getpeername"); + errno = se; + syslog(LOG_ERR, "getpeername: %m\n"); + exit(-1); + } else { + nl.nl_outip.s_addr = sin.sin_addr.s_addr; + nl.nl_outport = sin.sin_port; + } + + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + se = errno; + perror("ioctl"); + errno = se; + syslog(LOG_ERR, "ioctl: %m\n"); + exit(-1); + } + + sin.sin_port = nl.nl_realport; + sin.sin_addr = nl.nl_realip; + sl = sizeof(sin); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { + se = errno; + perror("connect"); + errno = se; + syslog(LOG_ERR, "connect: %m\n"); + exit(-1); + } + + (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + + syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); + if (relay(0, 1, fd) == -1) { + se = errno; + perror("relay"); + errno = se; + syslog(LOG_ERR, "relay: %m\n"); + exit(-1); + } + exit(0); +} diff --git a/share/examples/ipfilter/samples/userauth.c b/share/examples/ipfilter/samples/userauth.c new file mode 100644 index 000000000000..cc733a715322 --- /dev/null +++ b/share/examples/ipfilter/samples/userauth.c @@ -0,0 +1,61 @@ + +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <net/if.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_auth.h" + +extern int errno; + +main() +{ + struct frauth fra; + struct frauth *frap = &fra; + fr_info_t *fin = &fra.fra_info; + fr_ip_t *fi = &fin->fin_fi; + char yn[16]; + int fd; + + fd = open(IPL_NAME, O_RDWR); + fra.fra_len = 0; + fra.fra_buf = NULL; + while (ioctl(fd, SIOCAUTHW, &frap) == 0) { + if (fra.fra_info.fin_out) + fra.fra_pass = FR_OUTQUE; + else + fra.fra_pass = FR_INQUE; + + printf("%s ", inet_ntoa(fi->fi_src)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[0]); + printf("-> %s ", inet_ntoa(fi->fi_dst)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[1]); + printf("\n"); + printf("Allow packet through ? [y/n]"); + fflush(stdout); + if (!fgets(yn, sizeof(yn), stdin)) + break; + fflush(stdin); + if (yn[0] == 'n' || yn[0] == 'N') + fra.fra_pass |= FR_BLOCK; + else if (yn[0] == 'y' || yn[0] == 'Y') { + fra.fra_pass |= FR_PASS; + if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP) + fra.fra_pass |= FR_KEEPSTATE; + } else + fra.fra_pass |= FR_NOMATCH; + printf("answer = %c (%x), id %d idx %d\n", yn[0], + fra.fra_pass, fra.fra_info.fin_id, fra.fra_index); + if (ioctl(fd, SIOCAUTHR, &frap) != 0) + perror("SIOCAUTHR"); + } + fprintf(stderr, "errno=%d \n", errno); + perror("frauth-SIOCAUTHW"); +} diff --git a/share/examples/ipfw/change_rules.sh b/share/examples/ipfw/change_rules.sh new file mode 100755 index 000000000000..469b6a6c2e71 --- /dev/null +++ b/share/examples/ipfw/change_rules.sh @@ -0,0 +1,154 @@ +#!/bin/sh +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2000 Alexandre Peixoto +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Change ipfw(8) rules with safety guarantees for remote operation +# +# Invoke this script to edit ${firewall_script}. It will call ${EDITOR}, +# or vi(1) if the environment variable is not set, for you to edit +# ${firewall_script}, ask for confirmation, and then run +# ${firewall_script}. You can then examine the output of ipfw list and +# confirm whether you want the new version or not. +# +# If no answer is received in 30 seconds, the previous +# ${firewall_script} is run, restoring the old rules (this assumes ipfw +# flush is present in it). +# +# If the new rules are confirmed, they'll replace ${firewall_script} and +# the previous ones will be copied to ${firewall_script}.{date}. Mail +# will also be sent to root with a unified diff of the rule change. +# +# Unapproved rules are kept in ${firewall_script}.new, and you are +# offered the option of changing them instead of the present rules when +# you call this script. +# +# This script could be improved by using version control +# software. + +if [ -r /etc/defaults/rc.conf ]; then + . /etc/defaults/rc.conf + source_rc_confs +elif [ -r /etc/rc.conf ]; then + . /etc/rc.conf +fi + +EDITOR=${EDITOR:-/usr/bin/vi} +PAGER=${PAGER:-/usr/bin/more} + +tempfoo=`basename $0` +TMPFILE=`mktemp -t ${tempfoo}` || exit 1 + +get_yes_no() { + while true + do + echo -n "$1 (Y/N) ? " + read -t 30 a + if [ $? != 0 ]; then + a="No"; + return; + fi + case $a in + [Yy]) a="Yes"; + return;; + [Nn]) a="No"; + return;; + *);; + esac + done +} + +restore_rules() { + nohup sh ${firewall_script} </dev/null >/dev/null 2>&1 + rm ${TMPFILE} + exit 1 +} + +case "${firewall_type}" in +[Cc][Ll][Ii][Ee][Nn][Tt]|\ +[Cc][Ll][Oo][Ss][Ee][Dd]|\ +[Oo][Pp][Ee][Nn]|\ +[Ss][Ii][Mm][Pp][Ll][Ee]|\ +[Uu][Nn][Kk][Nn][Oo][Ww][Nn]) + edit_file="${firewall_script}" + rules_edit=no + ;; +*) + if [ -r "${firewall_type}" ]; then + edit_file="${firewall_type}" + rules_edit=yes + fi + ;; +esac + +if [ -f ${edit_file}.new ]; then + get_yes_no "A new rules file already exists, do you want to use it" + [ $a = 'No' ] && cp ${edit_file} ${edit_file}.new +else + cp ${edit_file} ${edit_file}.new +fi + +trap restore_rules SIGHUP + +${EDITOR} ${edit_file}.new + +get_yes_no "Do you want to install the new rules" + +[ $a = 'No' ] && exit 1 + +cat <<! +The rules will be changed now. If the message 'Type y to keep the new +rules' does not appear on the screen or the y key is not pressed in 30 +seconds, the original rules will be restored. +The TCP/IP connections might be broken during the change. If so, restore +the ssh/telnet connection being used. +! + +if [ ${rules_edit} = yes ]; then + nohup sh ${firewall_script} ${firewall_type}.new \ + < /dev/null > ${TMPFILE} 2>&1 +else + nohup sh ${firewall_script}.new \ + < /dev/null > ${TMPFILE} 2>&1 +fi +sleep 2; +get_yes_no "Would you like to see the resulting new rules" +[ $a = 'Yes' ] && ${PAGER} ${TMPFILE} +get_yes_no "Type y to keep the new rules" +[ $a != 'Yes' ] && restore_rules + +DATE=`date "+%Y%m%d%H%M"` +cp ${edit_file} ${edit_file}.$DATE +mv ${edit_file}.new ${edit_file} +cat <<! +The new rules are now installed. The previous rules have been preserved in +the file ${edit_file}.$DATE +! +diff -u ${edit_file}.$DATE ${edit_file} \ + | mail -s "`hostname` Firewall rule change" root +rm ${TMPFILE} +exit 0 diff --git a/share/examples/jails/README b/share/examples/jails/README new file mode 100644 index 000000000000..9d4513ac87cc --- /dev/null +++ b/share/examples/jails/README @@ -0,0 +1,66 @@ + +The below 4 samples require a VIMAGE enabled kernel: + + # (as root) + $ cp VIMAGE /usr/src/sys/amd64/conf/ + $ cd /usr/src + $ make KERNCONF=VIMAGE kernel + $ reboot + +FreeBSD 12 has VIMAGE enabled in GENERIC on amd64. +In that case, for jng simply load the ng_ether module first +(ng_bridge and ng_eiface will load on demand): + + # (as root) + # Load the ng_ether module at boot: + $ sysrc kld_list+=ng_ether + # Load ng_ether at once without rebooting: + $ kldload ng_ether + +Sample 1: jail.conf(5) + + $ cp jib jng /usr/sbin/ + $ cat jail.xxx.conf >> /etc/jail.conf + $ vi /etc/jail.conf + # NB: Customize root directory and bridge interface + $ sysrc jail_enable=YES + # NB: Assumes jail_list="" (meaning ``all jails in jail.conf'') + # NB: Assumes rc_conf_files="" (``below rc.conf(5) samples not used'') + $ service jail start + +Sample 2: rc.conf(5) + + $ cp jib jng /usr/sbin/ + $ cp rc.conf.jails /etc/ + $ vi /etc/rc.conf.jails + # NB: Customize root directory and bridge interface + $ sysrc rc_conf_files+=/etc/rc.conf.jails + # NB: Assumes /etc/jail.conf does not exist and jail_list="" + $ service jail start + +Sample 3: Per-jail jail.conf(5) + + $ cp jib jng /usr/sbin/ + $ cp jail.xxx.conf /etc/ + $ vi /etc/jail.xxx.conf + # NB: Customize root directory and bridge interface + $ sysrc jail_enable=YES + $ sysrc jail_list+=xxx + # NB: Assumes rc_conf_files="" + $ service jail start + +Sample 4: Per-jail rc.conf(5) + + $ cp jib jng /usr/sbin/ + $ cp rcjail.xxx.conf /etc/ + $ vi /etc/rcjail.xxx.conf + # NB: Customize root directory and bridge interface + $ sysrc jail_enable=YES + $ sysrc jail_list+=xxx + $ sysrc rc_conf_files+=/etc/rcjail.xxx.conf + # NB: Assumes neither /etc/jail.conf nor /etc/jail.xxx.conf exist + $ service jail start + +For additional recipes, see share/examples/netgraph for +making and hooking together jails using netgraph as the +virtual networking fabric. diff --git a/share/examples/jails/VIMAGE b/share/examples/jails/VIMAGE new file mode 100644 index 000000000000..51e8a593c68e --- /dev/null +++ b/share/examples/jails/VIMAGE @@ -0,0 +1,58 @@ + +################################################################################ +######################### VIMAGE KERNEL CONFIGURATION ########################## +################################################################################ + +#################### Inheritance + +# +# Inherit from, and override `GENERIC' +# +include GENERIC # Base configuration file +ident VIMAGE # Kernel name + +################################################################################ +##################### ENABLE NON-INHERITED OPTIONS/DEVICES ##################### +################################################################################ + +#################### Non-GENERIC options + +# +# Network Virtualization for Jails +# +options VIMAGE # vnet paravirtualization + +# +# Netgraph based bridging for vnet jails +# NB: Not strictly necessary; will load automatically via KLD when needed +# +options NETGRAPH # netgraph(4) system +options NETGRAPH_BRIDGE # ng_bridge(4) +options NETGRAPH_EIFACE # ng_eiface(4) +options NETGRAPH_ETHER # ng_ether(4) +options NETGRAPH_SOCKET # ng_socket(4) + +#################### Non-GENERIC devices + +# +# if_bridge based bridging for vnet jails +# NB: Not strictly necessary; will load automatically via KLD when needed +# +device epair # epair(4) +device if_bridge # if_bridge(4) + +################################################################################ +################ DISABLE UNNECESSARY INHERITED OPTIONS/DEVICES ################ +################################################################################ + +#################### Disable select inherited options + +# none + +#################### Disable select inherited devices + +# none + +################################################################################ +# END +################################################################################ diff --git a/share/examples/jails/jail.xxx.conf b/share/examples/jails/jail.xxx.conf new file mode 100644 index 000000000000..8ada4aa0dd9d --- /dev/null +++ b/share/examples/jails/jail.xxx.conf @@ -0,0 +1,34 @@ + +xxx { + host.hostname = "xxx.yyy"; # hostname + path = "/vm/xxx"; # root directory + + exec.clean; + exec.system_user = "root"; + exec.jail_user = "root"; + + # + # NB: Below 4-lines required + # + vnet; + # netgraph + vnet.interface = "ng0_xxx"; # vnet interface(s) + exec.prestart += "jng bridge xxx em0"; # bridge interface(s) + exec.poststop += "jng shutdown xxx"; # destroy interface(s) + # if_bridge + #vnet.interface = "e0b_xxx"; # vnet interface(s) + #exec.prestart += "jib addm xxx em0"; # bridge interface(s) + #exec.poststop += "jib destroy xxx"; # destroy interface(s) + + # Standard recipe + exec.start += "/bin/sh /etc/rc"; + exec.stop = "/bin/sh /etc/rc.shutdown jail"; + exec.consolelog = "/var/log/jail_xxx_console.log"; + mount.devfs; # mount devfs + + # Optional (default off) + #devfs_ruleset = "11"; # rule to unhide bpf for DHCP + #allow.mount; # mount /etc/fstab.xxx + #allow.set_hostname = 1; # Allow hostname to change + #allow.sysvipc = 1; # Allow SysV Interprocess Comm. +} diff --git a/share/examples/jails/jib b/share/examples/jails/jib new file mode 100755 index 000000000000..55d908438b3e --- /dev/null +++ b/share/examples/jails/jib @@ -0,0 +1,417 @@ +#!/bin/sh +#- +# Copyright (c) 2016 Devin Teske +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +############################################################ IDENT(1) +# +# $Title: if_bridge(4) management script for vnet jails $ +# +############################################################ INFORMATION +# +# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to +# manage `vnet' interfaces for jails. Designed to automate the creation of vnet +# interface(s) during jail `prestart' and destroy said interface(s) during jail +# `poststop'. +# +# In jail.conf(5) format: +# +# ### BEGIN EXCERPT ### +# +# xxx { +# host.hostname = "xxx.yyy"; +# path = "/vm/xxx"; +# +# # +# # NB: Below 2-lines required +# # NB: The number of eNb_xxx interfaces should match the number of +# # arguments given to `jib addm xxx' in exec.prestart value. +# # +# vnet; +# vnet.interface = e0b_xxx, e1b_xxx, ...; +# +# exec.clean; +# exec.system_user = "root"; +# exec.jail_user = "root"; +# +# # +# # NB: Below 2-lines required +# # NB: The number of arguments after `jib addm xxx' should match +# # the number of eNb_xxx arguments in vnet.interface value. +# # +# exec.prestart += "jib addm xxx em0 em1 ..."; +# exec.poststop += "jib destroy xxx"; +# +# # Standard recipe +# exec.start += "/bin/sh /etc/rc"; +# exec.stop = "/bin/sh /etc/rc.shutdown jail"; +# exec.consolelog = "/var/log/jail_xxx_console.log"; +# mount.devfs; +# +# # Optional (default off) +# #allow.mount; +# #allow.set_hostname = 1; +# #allow.sysvipc = 1; +# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP +# } +# +# ### END EXCERPT ### +# +# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist): +# +# ### BEGIN EXCERPT ### +# +# jail_enable="YES" +# jail_list="xxx" +# +# # +# # Global presets for all jails +# # +# jail_devfs_enable="YES" # mount devfs +# +# # +# # Global options (default off) +# # +# #jail_mount_enable="YES" # mount /etc/fstab.{name} +# #jail_set_hostname_allow="YES" # Allow hostname to change +# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm. +# +# # xxx +# jail_xxx_hostname="xxx.shxd.cx" # hostname +# jail_xxx_rootdir="/vm/xxx" # root directory +# jail_xxx_vnet_interfaces="e0b_xxx e1bxxx ..." # vnet interface(s) +# jail_xxx_exec_prestart0="jib addm xxx em0 em1 ..." # bridge interface(s) +# jail_xxx_exec_poststop0="jib destroy xxx" # destroy interface(s) +# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx +# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP +# +# ### END EXCERPT ### +# +# Note that the legacy rc.conf(5) format is converted to +# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing. +# +# ASIDE: dhclient(8) inside a vnet jail... +# +# To allow dhclient(8) to work inside a vnet jail, make sure the following +# appears in /etc/devfs.rules (which should be created if it doesn't exist): +# +# [devfsrules_jail=11] +# add include $devfsrules_hide_all +# add include $devfsrules_unhide_basic +# add include $devfsrules_unhide_login +# add path 'bpf*' unhide +# +# And set ether devfs.ruleset="11" (jail.conf(5)) or +# jail_{name}_devfs_ruleset="11" (rc.conf(5)). +# +# NB: While this tool can't create every type of desirable topology, it should +# handle most setups, minus some which considered exotic or purpose-built. +# +############################################################ GLOBALS + +pgm="${0##*/}" # Program basename + +# +# Global exit status +# +SUCCESS=0 +FAILURE=1 + +############################################################ FUNCTIONS + +usage() +{ + local action usage descr + exec >&2 + echo "Usage: $pgm action [arguments]" + echo "Actions:" + for action in \ + addm \ + show \ + show1 \ + destroy \ + ; do + eval usage=\"\$jib_${action}_usage\" + [ "$usage" ] || continue + eval descr=\"\$jib_${action}_descr\" + printf "\t%s\n\t\t%s\n" "$usage" "$descr" + done + exit $FAILURE +} + +action_usage() +{ + local usage descr action="$1" + eval usage=\"\$jib_${action}_usage\" + echo "Usage: $pgm $usage" >&2 + eval descr=\"\$jib_${action}_descr\" + printf "\t%s\n" "$descr" + exit $FAILURE +} + +derive_mac() +{ + local OPTIND=1 OPTARG __flag + local __mac_num= __make_pair= + while getopts 2n: __flag; do + case "$__flag" in + 2) __make_pair=1 ;; + n) __mac_num=${OPTARG%%[^0-9]*} ;; + esac + done + shift $(( $OPTIND - 1 )) + + if [ ! "$__mac_num" ]; then + eval __mac_num=\${_${iface}_num:--1} + __mac_num=$(( $__mac_num + 1 )) + eval _${iface}_num=\$__mac_num + fi + + local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4" + local __iface_devid __new_devid __num __new_devid_b + # + # Calculate MAC address derived from given iface. + # + # The formula I'm using is ``NP:SS:SS:II:II:II'' where: + # + N denotes 4 bits used as a counter to support branching + # each parent interface up to 15 times under the same jail + # name (see S below). + # + P denotes the special nibble whose value, if one of + # 2, 6, A, or E (but usually 2) denotes a privately + # administered MAC address (while remaining routable). + # + S denotes 16 bits, the sum(1) value of the jail name. + # + I denotes bits that are inherited from parent interface. + # + # The S bits are a CRC-16 checksum of NAME, allowing the jail + # to change link numbers in ng_bridge(4) without affecting the + # MAC address. Meanwhile, if... + # + the jail NAME changes (e.g., it was duplicated and given + # a new name with no other changes) + # + the underlying network interface changes + # + the jail is moved to another host + # the MAC address will be recalculated to a new, similarly + # unique value preventing conflict. + # + __iface_devid=$( ifconfig $__iface ether | awk '/ether/,$0=$2' ) + # ??:??:??:II:II:II + __new_devid=${__iface_devid#??:??:??} # => :II:II:II + # => :SS:SS:II:II:II + __num=$( set -- `echo -n "$__name" | sum` && echo $1 ) + __new_devid=$( printf :%02x:%02x \ + $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid + # => P:SS:SS:II:II:II + case "$__iface_devid" in + ?2:*) __new_devid=a$__new_devid __new_devid_b=e$__new_devid ;; + ?[Ee]:*) __new_devid=2$__new_devid __new_devid_b=6$__new_devid ;; + *) __new_devid=2$__new_devid __new_devid_b=e$__new_devid + esac + # => NP:SS:SS:II:II:II + __new_devid=$( printf %x $(( $__mac_num & 15 )) )$__new_devid + __new_devid_b=$( printf %x $(( $__mac_num & 15 )) )$__new_devid_b + + # + # Return derivative MAC address(es) + # + if [ "$__make_pair" ]; then + if [ "$__var_to_set" -a "$__var_to_set_b" ]; then + eval $__var_to_set=\$__new_devid + eval $__var_to_set_b=\$__new_devid_b + else + echo $__new_devid $__new_devid_b + fi + else + if [ "$__var_to_set" ]; then + eval $__var_to_set=\$__new_devid + else + echo $__new_devid + fi + fi +} + +mustberoot_to_continue() +{ + if [ "$( id -u )" -ne 0 ]; then + echo "Must run as root!" >&2 + exit $FAILURE + fi +} + +jib_addm_usage="addm [-b BRIDGE_NAME] NAME [!]iface0 [[!]iface1 ...]" +jib_addm_descr="Creates e0b_NAME [e1b_NAME ...]" +jib_addm() +{ + local OPTIND=1 OPTARG flag bridge=bridge + while getopts b: flag; do + case "$flag" in + b) bridge="${OPTARG:-bridge}" ;; + *) action_usage addm # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + + local name="$1" + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] || + action_usage addm # NOTREACHED + shift 1 # name + + mustberoot_to_continue + + local iface eiface_devid_a eiface_devid_b + local new no_derive num quad i=0 + for iface in $*; do + + no_derive= + case "$iface" in + !*) iface=${iface#!} no_derive=1 ;; + esac + + # Make sure the interface doesn't exist already + if ifconfig "e${i}a_$name" > /dev/null 2>&1; then + i=$(( $i + 1 )) + continue + fi + + # Bring the interface up + ifconfig $iface up || return + + # Make sure the interface has been bridged + if ! ifconfig "$iface$bridge" > /dev/null 2>&1; then + new=$( ifconfig bridge create ) || return + ifconfig $new addm $iface || return + ifconfig $new name "$iface$bridge" || return + ifconfig "$iface$bridge" up || return + fi + + # Create a new interface to the bridge + new=$( ifconfig epair create ) || return + ifconfig "$iface$bridge" addm $new || return + + # Rename the new interface + ifconfig $new name "e${i}a_$name" || return + ifconfig ${new%a}b name "e${i}b_$name" || return + ifconfig "e${i}a_$name" up || return + ifconfig "e${i}b_$name" up || return + + # + # Set the MAC address of the new interface using a sensible + # algorithm to prevent conflicts on the network. + # + eiface_devid_a= eiface_devid_b= + [ "$no_derive" ] || derive_mac -2 $iface "$name" \ + eiface_devid_a eiface_devid_b + if [ "$eiface_devid_a" -a "$eiface_devid_b" ]; then + ifconfig "e${i}a_$name" ether $eiface_devid_a + ifconfig "e${i}b_$name" ether $eiface_devid_b + fi > /dev/null 2>&1 + + i=$(( $i + 1 )) + done # for iface +} + +jib_show_usage="show" +jib_show_descr="List possible NAME values for \`show NAME'" +jib_show1_usage="show NAME" +jib_show1_descr="Lists e0b_NAME [e1b_NAME ...]" +jib_show2_usage="show [NAME]" +jib_show() +{ + local OPTIND=1 OPTARG flag + while getopts "" flag; do + case "$flag" in + *) action_usage show2 # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + if [ $# -eq 0 ]; then + ifconfig | awk ' + /^[^:[:space:]]+:/ { + iface = $1 + sub(/:.*/, "", iface) + next + } + $1 == "groups:" { + for (n = split($0, group); n > 1; n--) { + if (group[n] != "bridge") continue + print iface + next + } + }' | + xargs -rn1 ifconfig | + awk '$1 == "member:" && + sub(/^e[[:digit:]]+a_/, "", $2), $0 = $2' | + sort -u + return + fi + ifconfig | awk -v name="$1" ' + match($0, /^e[[:digit:]]+a_/) && sub(/:.*/, "") && + substr($1, RSTART + RLENGTH) == name + ' | sort +} + +jib_destroy_usage="destroy NAME" +jib_destroy_descr="Destroy e0b_NAME [e1b_NAME ...]" +jib_destroy() +{ + local OPTIND=1 OPTARG flag + while getopts "" flag; do + case "$flag" in + *) action_usage destroy # NOTREACHED + esac + done + shift $(( $OPTIND -1 )) + local name="$1" + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || + action_usage destroy # NOTREACHED + mustberoot_to_continue + jib_show "$name" | xargs -rn1 -I eiface ifconfig eiface destroy +} + +############################################################ MAIN + +# +# Command-line arguments +# +action="$1" +[ "$action" ] || usage # NOTREACHED + +# +# Validate action argument +# +if [ "$BASH_VERSION" ]; then + type="$( type -t "jib_$action" )" || usage # NOTREACHED +else + type="$( type "jib_$action" 2> /dev/null )" || usage # NOTREACHED +fi +case "$type" in +*function) + shift 1 # action + eval "jib_$action" \"\$@\" + ;; +*) usage # NOTREACHED +esac + +################################################################################ +# END +################################################################################ diff --git a/share/examples/jails/jng b/share/examples/jails/jng new file mode 100755 index 000000000000..610b08f96840 --- /dev/null +++ b/share/examples/jails/jng @@ -0,0 +1,508 @@ +#!/bin/sh +#- +# Copyright (c) 2016 Devin Teske +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +############################################################ IDENT(1) +# +# $Title: netgraph(4) management script for vnet jails $ +# +############################################################ INFORMATION +# +# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to +# manage `vnet' interfaces for jails. Designed to automate the creation of vnet +# interface(s) during jail `prestart' and destroy said interface(s) during jail +# `poststop'. +# +# In jail.conf(5) format: +# +# ### BEGIN EXCERPT ### +# +# xxx { +# host.hostname = "xxx.yyy"; +# path = "/vm/xxx"; +# +# # +# # NB: Below 2-lines required +# # NB: The number of ngN_xxx interfaces should match the number of +# # arguments given to `jng bridge xxx' in exec.prestart value. +# # +# vnet; +# vnet.interface = ng0_xxx, ng1_xxx, ...; +# +# exec.clean; +# exec.system_user = "root"; +# exec.jail_user = "root"; +# +# # +# # NB: Below 2-lines required +# # NB: The number of arguments after `jng bridge xxx' should match +# # the number of ngN_xxx arguments in vnet.interface value. +# # +# exec.prestart += "jng bridge xxx em0 em1 ..."; +# exec.poststop += "jng shutdown xxx"; +# +# # Standard recipe +# exec.start += "/bin/sh /etc/rc"; +# exec.stop = "/bin/sh /etc/rc.shutdown jail"; +# exec.consolelog = "/var/log/jail_xxx_console.log"; +# mount.devfs; +# +# # Optional (default off) +# #allow.mount; +# #allow.set_hostname = 1; +# #allow.sysvipc = 1; +# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP +# } +# +# ### END EXCERPT ### +# +# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist): +# +# ### BEGIN EXCERPT ### +# +# jail_enable="YES" +# jail_list="xxx" +# +# # +# # Global presets for all jails +# # +# jail_devfs_enable="YES" # mount devfs +# +# # +# # Global options (default off) +# # +# #jail_mount_enable="YES" # mount /etc/fstab.{name} +# #jail_set_hostname_allow="YES" # Allow hostname to change +# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm. +# +# # xxx +# jail_xxx_hostname="xxx.shxd.cx" # hostname +# jail_xxx_rootdir="/vm/xxx" # root directory +# jail_xxx_vnet_interfaces="ng0_xxx ng1xxx ..." # vnet interface(s) +# jail_xxx_exec_prestart0="jng bridge xxx em0 em1 ..." # bridge interface(s) +# jail_xxx_exec_poststop0="jng shutdown xxx" # destroy interface(s) +# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx +# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP +# +# ### END EXCERPT ### +# +# Note that the legacy rc.conf(5) format is converted to +# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing. +# +# ASIDE: dhclient(8) inside a vnet jail... +# +# To allow dhclient(8) to work inside a vnet jail, make sure the following +# appears in /etc/devfs.rules (which should be created if it doesn't exist): +# +# [devfsrules_jail=11] +# add include $devfsrules_hide_all +# add include $devfsrules_unhide_basic +# add include $devfsrules_unhide_login +# add path 'bpf*' unhide +# +# And set ether devfs.ruleset="11" (jail.conf(5)) or +# jail_{name}_devfs_ruleset="11" (rc.conf(5)). +# +# NB: While this tool can't create every type of desirable topology, it should +# handle most setups, minus some which considered exotic or purpose-built. +# +############################################################ GLOBALS + +pgm="${0##*/}" # Program basename + +# +# Global exit status +# +SUCCESS=0 +FAILURE=1 + +############################################################ FUNCTIONS + +usage() +{ + local action usage descr + exec >&2 + echo "Usage: $pgm action [arguments]" + echo "Actions:" + for action in \ + bridge \ + graph \ + show \ + show1 \ + shutdown \ + stats \ + ; do + eval usage=\"\$jng_${action}_usage\" + [ "$usage" ] || continue + eval descr=\"\$jng_${action}_descr\" + printf "\t%s\n\t\t%s\n" "$usage" "$descr" + done + exit $FAILURE +} + +action_usage() +{ + local usage descr action="$1" + eval usage=\"\$jng_${action}_usage\" + echo "Usage: $pgm $usage" >&2 + eval descr=\"\$jng_${action}_descr\" + printf "\t%s\n" "$descr" + exit $FAILURE +} + +derive_mac() +{ + local OPTIND=1 OPTARG __flag + local __mac_num= __make_pair= + while getopts 2n: __flag; do + case "$__flag" in + 2) __make_pair=1 ;; + n) __mac_num=${OPTARG%%[^0-9]*} ;; + esac + done + shift $(( $OPTIND - 1 )) + + if [ ! "$__mac_num" ]; then + eval __mac_num=\${_${iface}_num:--1} + __mac_num=$(( $__mac_num + 1 )) + eval _${iface}_num=\$__mac_num + fi + + local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4" + local __iface_devid __new_devid __num __new_devid_b + # + # Calculate MAC address derived from given iface. + # + # The formula I'm using is ``NP:SS:SS:II:II:II'' where: + # + N denotes 4 bits used as a counter to support branching + # each parent interface up to 15 times under the same jail + # name (see S below). + # + P denotes the special nibble whose value, if one of + # 2, 6, A, or E (but usually 2) denotes a privately + # administered MAC address (while remaining routable). + # + S denotes 16 bits, the sum(1) value of the jail name. + # + I denotes bits that are inherited from parent interface. + # + # The S bits are a CRC-16 checksum of NAME, allowing the jail + # to change link numbers in ng_bridge(4) without affecting the + # MAC address. Meanwhile, if... + # + the jail NAME changes (e.g., it was duplicated and given + # a new name with no other changes) + # + the underlying network interface changes + # + the jail is moved to another host + # the MAC address will be recalculated to a new, similarly + # unique value preventing conflict. + # + __iface_devid=$( ifconfig $__iface ether | awk '/ether/,$0=$2' ) + # ??:??:??:II:II:II + __new_devid=${__iface_devid#??:??:??} # => :II:II:II + # => :SS:SS:II:II:II + __num=$( set -- `echo -n "$__name" | sum` && echo $1 ) + __new_devid=$( printf :%02x:%02x \ + $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid + # => P:SS:SS:II:II:II + case "$__iface_devid" in + ?2:*) __new_devid=a$__new_devid __new_devid_b=e$__new_devid ;; + ?[Ee]:*) __new_devid=2$__new_devid __new_devid_b=6$__new_devid ;; + *) __new_devid=2$__new_devid __new_devid_b=e$__new_devid + esac + # => NP:SS:SS:II:II:II + __new_devid=$( printf %x $(( $__mac_num & 15 )) )$__new_devid + __new_devid_b=$( printf %x $(( $__mac_num & 15 )) )$__new_devid_b + + # + # Return derivative MAC address(es) + # + if [ "$__make_pair" ]; then + if [ "$__var_to_set" -a "$__var_to_set_b" ]; then + eval $__var_to_set=\$__new_devid + eval $__var_to_set_b=\$__new_devid_b + else + echo $__new_devid $__new_devid_b + fi + else + if [ "$__var_to_set" ]; then + eval $__var_to_set=\$__new_devid + else + echo $__new_devid + fi + fi +} + +mustberoot_to_continue() +{ + if [ "$( id -u )" -ne 0 ]; then + echo "Must run as root!" >&2 + exit $FAILURE + fi +} + +jng_bridge_usage="bridge [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]" +jng_bridge_descr="Create ng0_NAME [ng1_NAME ...]" +jng_bridge() +{ + local OPTIND=1 OPTARG flag bridge=bridge + while getopts b: flag; do + case "$flag" in + b) bridge="$OPTARG" + [ "$bridge" ] || action_usage bridge ;; # NOTREACHED + *) action_usage bridge # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + + local name="$1" + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] || + action_usage bridge # NOTREACHED + shift 1 # name + + mustberoot_to_continue + + local iface parent eiface eiface_devid + local new clone_mac no_derive num quad i=0 + for iface in $*; do + + clone_mac= + no_derive= + case "$iface" in + =*) iface=${iface#=} clone_mac=1 ;; + !*) iface=${iface#!} no_derive=1 ;; + esac + + # Make sure the interface doesn't exist already + eiface=ng${i}_$name + if ngctl msg "$eiface:" getifname > /dev/null 2>&1; then + i=$(( $i + 1 )) + continue + fi + + # Bring the interface up + ifconfig $iface up || return + + # Set promiscuous mode and don't overwrite src addr + ngctl msg $iface: setpromisc 1 || return + ngctl msg $iface: setautosrc 0 || return + + # Make sure the interface has been bridged + if ! ngctl info ${iface}bridge: > /dev/null 2>&1; then + ngctl mkpeer $iface: bridge lower link0 || return + ngctl connect $iface: $iface:lower upper link1 || + return + ngctl name $iface:lower ${iface}bridge || return + fi + + # Optionally create a secondary bridge + if [ "$bridge" != "bridge" ] && + ! ngctl info "$iface$bridge:" > /dev/null 2>&1 + then + num=2 + while ngctl msg ${iface}bridge: getstats $num \ + > /dev/null 2>&1 + do + num=$(( $num + 1 )) + done + ngctl mkpeer $iface:lower bridge link$num link1 || + return + ngctl name ${iface}bridge:link$num "$iface$bridge" || + return + fi + + # Create a new interface to the bridge + num=2 + while ngctl msg "$iface$bridge:" getstats $num > /dev/null 2>&1 + do + num=$(( $num + 1 )) + done + ngctl mkpeer "$iface$bridge:" eiface link$num ether || return + + # Rename the new interface + while [ ${#eiface} -gt 15 ]; do # OS limitation + eiface=${eiface%?} + done + new=$( set -- `ngctl show -n "$iface$bridge:link$num"` && + echo $2 ) || return + ngctl name "$iface$bridge:link$num" $eiface || return + ifconfig $new name $eiface || return + ifconfig $eiface up || return + + # + # Set the MAC address of the new interface using a sensible + # algorithm to prevent conflicts on the network. + # + eiface_devid= + if [ "$clone_mac" ]; then + eiface_devid=$( ifconfig $iface ether | + awk '/ether/,$0=$2' ) + elif [ ! "$no_derive" ]; then + derive_mac $iface "$name" eiface_devid + fi + [ "$eiface_devid" ] && + ifconfig $eiface ether $eiface_devid > /dev/null 2>&1 + + i=$(( $i + 1 )) + done # for iface +} + +jng_graph_usage="graph [-f] [-T type] [-o output]" +jng_graph_descr="Generate network graph (default output is \`jng.svg')" +jng_graph() +{ + local OPTIND=1 OPTARG flag + local output=jng.svg output_type= force= + while getopts fo:T: flag; do + case "$flag" in + f) force=1 ;; + o) output="$OPTARG" ;; + T) output_type="$OPTARG" ;; + *) action_usage graph # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + [ $# -eq 0 -a "$output" ] || action_usage graph # NOTREACHED + mustberoot_to_continue + if [ -e "$output" -a ! "$force" ]; then + echo "$output: Already exists (use \`-f' to overwrite)" >&2 + return $FAILURE + fi + if [ ! "$output_type" ]; then + local valid suffix + valid=$( dot -Txxx 2>&1 ) + for suffix in ${valid##*:}; do + [ "$output" != "${output%.$suffix}" ] || continue + output_type=$suffix + break + done + fi + ngctl dot | dot ${output_type:+-T "$output_type"} -o "$output" +} + +jng_show_usage="show" +jng_show_descr="List possible NAME values for \`show NAME'" +jng_show1_usage="show NAME" +jng_show1_descr="Lists ng0_NAME [ng1_NAME ...]" +jng_show2_usage="show [NAME]" +jng_show() +{ + local OPTIND=1 OPTARG flag + while getopts "" flag; do + case "$flag" in + *) action_usage show2 # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + mustberoot_to_continue + if [ $# -eq 0 ]; then + ngctl ls | awk '$4=="bridge",$0=$2' | + xargs -rn1 -Ibridge ngctl show bridge: | + awk 'sub(/^ng[[:digit:]]+_/, "", $2), $0 = $2' | + sort -u + return + fi + ngctl ls | awk -v name="$1" ' + match($2, /^ng[[:digit:]]+_/) && + substr($2, RSTART + RLENGTH) == name && + $4 == "eiface", $0 = $2 + ' | sort +} + +jng_shutdown_usage="shutdown NAME" +jng_shutdown_descr="Shutdown ng0_NAME [ng1_NAME ...]" +jng_shutdown() +{ + local OPTIND=1 OPTARG flag + while getopts "" flag; do + case "$flag" in + *) action_usage shutdown # NOTREACHED + esac + done + shift $(( $OPTIND -1 )) + local name="$1" + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || + action_usage shutdown # NOTREACHED + mustberoot_to_continue + jng_show "$name" | xargs -rn1 -I eiface ngctl shutdown eiface: +} + +jng_stats_usage="stats NAME" +jng_stats_descr="Show ng_bridge link statistics for NAME interfaces" +jng_stats() +{ + local OPTIND=1 OPTARG flag + while getopts "" flag; do + case "$flag" in + *) action_usage stats # NOTREACHED + esac + done + shift $(( $OPTIND -1 )) + local name="$1" + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || + action_usage stats # NOTREACHED + mustberoot_to_continue + for eiface in $( jng_show "$name" ); do + echo "$eiface:" + ngctl show $eiface: | awk ' + $3 == "bridge" && $5 ~ /^link/ { + bridge = $2 + link = substr($5, 5) + system(sprintf("ngctl msg %s: getstats %u", + bridge, link)) + }' | fmt 2 | awk ' + /=/ && fl = index($0, "=") { + printf "%20s = %s\n", + substr($0, 0, fl-1), + substr($0, 0, fl+1) + } + ' # END-QUOTE + done +} + +############################################################ MAIN + +# +# Command-line arguments +# +action="$1" +[ "$action" ] || usage # NOTREACHED + +# +# Validate action argument +# +if [ "$BASH_VERSION" ]; then + type="$( type -t "jng_$action" )" || usage # NOTREACHED +else + type="$( type "jng_$action" 2> /dev/null )" || usage # NOTREACHED +fi +case "$type" in +*function) + shift 1 # action + eval "jng_$action" \"\$@\" + ;; +*) usage # NOTREACHED +esac + +################################################################################ +# END +################################################################################ diff --git a/share/examples/jails/rc.conf.jails b/share/examples/jails/rc.conf.jails new file mode 100644 index 000000000000..b1e0d6187b4e --- /dev/null +++ b/share/examples/jails/rc.conf.jails @@ -0,0 +1,75 @@ + +############################################################################### +############################# JAIL CONFIGURATIONS ############################# +############################################################################### + +jail_enable="YES" +jail_list="XXX" + +# +# Global presets for all jails +# +jail_devfs_enable="YES" # mount devfs +# Optional (default off) +#jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm. +#jail_set_hostname_allow="YES" # Allow hostname to change + +# +# To allow dhclient(8) to work inside a jail, make sure the following appears +# in /etc/devfs.rules (which should be created if it doesn't exist): +# +# [devfsrules_jail=11] +# add include $devfsrules_hide_all +# add include $devfsrules_unhide_basic +# add include $devfsrules_unhide_login +# add path 'bpf*' unhide +# + +############################################################ JAILS + +# NETGRAPH TEMPLATE (copy/pate; then replace {name} with short name for jail) +# +# {name} +# +#jail_{name}_hostname="{name}.shxd.cx" # hostname +#jail_{name}_rootdir="/vm/{name}" # root directory +#jail_{name}_vnet_interfaces="ng0_{name}" # vnet interface(s) +#jail_{name}_exec_prestart0="jng bridge {name} em0" # bridge interface(s) +#jail_{name}_exec_poststop0="jng shutdown {name}" # destroy interface(s) +# Optional (default off) +#jail_{name}_devfs_ruleset="11" # rule to unhide bpf for DHCP +#jail_{name}_mount_enable="YES" # mount /etc/fstab.{name} + +# IF_BRIDGE TEMPLATE (copy/pate; then replace {name} with short name for jail) +# +# {name} +# +#jail_{name}_hostname="{name}.shxd.cx" # hostname +#jail_{name}_rootdir="/vm/{name}" # root directory +#jail_{name}_vnet_interfaces="e0b_{name}" # vnet interface(s) +#jail_{name}_exec_prestart0="jib addm {name} em0" # bridge interface(s) +#jail_{name}_exec_poststop0="jib destroy {name}" # destroy interface(s) +# Optional (default off) +#jail_{name}_devfs_ruleset="11" # rule to unhide bpf for DHCP +#jail_{name}_mount_enable="YES" # mount /etc/fstab.{name} + +# +# XXX +# +jail_XXX_hostname="XXX.YYY" # hostname +jail_XXX_rootdir="/vm/XXX" # root directory +# netgraph +jail_XXX_vnet_interface="ng0_XXX" # vnet interface(s) +jail_XXX_exec_prestart0="jng bridge XXX em0" # bridge interface(s) +jail_XXX_exec_poststop0="jng shutdown XXX" # destroy interface(s) +# if_bridge +#jail_XXX_vnet_interface="e0b_XXX" # vnet interface(s) +#jail_XXX_exec_prestart0="jib addm XXX em0" # bridge interface(s) +#jail_XXX_exec_poststop0="jib destroy XXX" # destroy interface(s) +# Optional (default off) +#jail_XXX_devfs_ruleset="11" # rule to unhide bpf for DHCP +#jail_XXX_mount_enable="YES" # mount /etc/fstab.XXX + +################################################################################ +# END +################################################################################ diff --git a/share/examples/jails/rcjail.xxx.conf b/share/examples/jails/rcjail.xxx.conf new file mode 100644 index 000000000000..8757219a97f3 --- /dev/null +++ b/share/examples/jails/rcjail.xxx.conf @@ -0,0 +1,24 @@ + +jail_XXX_hostname="XXX.YYY" # hostname +jail_XXX_rootdir="/vm/XXX" # root directory + +# +# NB: Below 3 lines required +# +# netgraph +jail_XXX_vnet_interface="ng0_XXX" # vnet interface(s) +jail_XXX_exec_prestart0="jng bridge XXX em0" # bridge interface(s) +jail_XXX_exec_poststop0="jng shutdown XXX" # destroy interface(s) +# if_bridge +#jail_XXX_vnet_interface="e0b_XXX" # vnet interface(s) +#jail_XXX_exec_prestart0="jib addm XXX em0" # bridge interface(s) +#jail_XXX_exec_poststop0="jib destroy XXX" # destroy interface(s) + +# Standard recipe +jail_XXX_devfs_enable="YES" # mount devfs + +# Optional (default off) +#jail_XXX_devfs_ruleset="11" # rule to unhide bpf for DHCP +#jail_XXX_mount_enable="YES" # mount /etc/fstab.XXX +#jail_XXX_set_hostname_allow="YES" # Allow hostname to change +#jail_XXX_sysvipc_allow="YES" # Allow SysV Interprocess Comm. diff --git a/share/examples/kld/Makefile b/share/examples/kld/Makefile new file mode 100644 index 000000000000..3116f547e057 --- /dev/null +++ b/share/examples/kld/Makefile @@ -0,0 +1,73 @@ +# 08 Nov 1998 +# +# Makefile for sample programs for kld modules package +# +# 08 Nov 1998 Rajesh Vaidheeswarran - adapted from lkm Makefile +# +# Copyright (c) 1998 Rajesh Vaidheeswarran +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Rajesh Vaidheeswarran. +# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Copyright (c) 1993 Terrence R. Lambert. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Terrence R. Lambert. +# 4. The name Terrence R. Lambert may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld +SUBDIR= cdev dyn_sysctl firmware khelp random_adaptor syscall + +.include <bsd.subdir.mk> diff --git a/share/examples/kld/cdev/Makefile b/share/examples/kld/cdev/Makefile new file mode 100644 index 000000000000..706cb2dcbae9 --- /dev/null +++ b/share/examples/kld/cdev/Makefile @@ -0,0 +1,8 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/cdev +SUBDIR= module test + +load unload: _SUBDIR + +.include <bsd.subdir.mk> diff --git a/share/examples/kld/cdev/README b/share/examples/kld/cdev/README new file mode 100644 index 000000000000..617a3460f86d --- /dev/null +++ b/share/examples/kld/cdev/README @@ -0,0 +1,130 @@ +# Copyright (c) 1998 Rajesh Vaidheeswarran +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Rajesh Vaidheeswarran +# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Copyright (c) 1993 Terrence R. Lambert. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Terrence R. Lambert. +# 4. The name Terrence R. Lambert may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# + +1.0 Overview + + This is the README file for the sample kld module + that mimics a character device driver. + + A kld module may be used to load any data or + program into the kernel that can be made available by + modifying a table, pointer, or other kernel data to inform + the kernel that the module should be used instead of the + previous code/data path. + + Generally, it is assumed that a loadable module is one of + a set of similar modules (such as a file system or console + terminal emulation), and that the reference is through a + table (such as vfssw[]), and that a "special" value is + assigned to the slots which are allowed to be replaced. + This is not enforced, so you may use the kld module + any way you see fit. + + As with the loadable system calls, it may be desirable to + allow the module loader to replace an *existing* entry to + try out changes to kernel code without rebuilding and + booting from the new kernel. + + The idea behind this example is to show some interaction + with the device driver. Therefore the flow of the code that + this driver is aimed at is as follows: + + open(2) -> ioctl(2) -> write(2) -> read(2) -> close(2). + + We will first open the device in the /dev/ directory; then + we will send an ioctl message to it using ioctl(2) call; + then write a small string via the write(2) call. This string + we write to the device will be stored in a static buffer, + and later will be accessible via the read(2) call. Finally, + we will close(2) our open()'d device so that we may no + longer make read or write calls on it. + +2.0 Directions + + To test the module, do the following: + + cd module + make load + + A load message (the copyright) will be printed on the console. + + cd ../test + make load + + The system call prints a message on the console when called. + This message will be printed when running "make load" in + the "test" subdirectory. + + +3.0 Recovering resources + + The module consumes memory when loaded; it can be freed up by + unloading it. To unload it, type the following from the directory + this file is in: + + cd module + make unload + + The miscellaneous module will be unloaded by name. + + +4.0 END OF DOCUMENT diff --git a/share/examples/kld/cdev/module/Makefile b/share/examples/kld/cdev/module/Makefile new file mode 100644 index 000000000000..7db8ca7442c6 --- /dev/null +++ b/share/examples/kld/cdev/module/Makefile @@ -0,0 +1,8 @@ +# Makefile for kld char device driver. + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/${KMOD}/module +KMOD= cdev +SRCS= cdev.c cdevmod.c + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/cdev/module/cdev.c b/share/examples/kld/cdev/module/cdev.c new file mode 100644 index 000000000000..9d10e8d03f98 --- /dev/null +++ b/share/examples/kld/cdev/module/cdev.c @@ -0,0 +1,182 @@ +/* 08 Nov 1998*/ +/*- + * cdev.c + * + * 08 Nov 1998 Rajesh Vaidheeswarran + * + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1998 Rajesh Vaidheeswarran + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Rajesh Vaidheeswarran. + * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1993 Terrence R. Lambert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <sys/param.h> +#include <sys/uio.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/ioccom.h> +#include <sys/conf.h> + +#include "cdev.h" + +/* + * This is the actual code for the system call... it can't be static because + * it is exported to another part of the module... the only place it needs + * to be referenced is the sysent we are interested in. + * + * To write your own system call using this as a template, you could strip + * out this code and use the rest as a prototype module, changing only the + * function names and the number of arguments to the call in the module + * specific "sysent". + * + * You would have to use the "-R" option of "ld" to ensure a linkable file + * if you were to do this, since you would need to combine multiple ".o" + * files into a single ".o" file for use by "modload". + */ + +#define CDEV_IOCTL1 _IOR('C', 1, u_int) + +/* Stores string recv'd by _write() */ +static char buf[512+1]; +static size_t len; + +int +mydev_open(struct cdev *dev, int flag, int otyp, struct thread *td) +{ + struct proc *procp = td->td_proc; + + printf("mydev_open: dev_t=%lu, flag=%x, otyp=%x, procp=%p\n", + dev2udev(dev), flag, otyp, procp); + memset(&buf, '\0', 513); + len = 0; + return (0); +} + +int +mydev_close(struct cdev *dev, int flag, int otyp, struct thread *td) +{ + struct proc *procp = td->td_proc; + + printf("mydev_close: dev_t=%lu, flag=%x, otyp=%x, procp=%p\n", + dev2udev(dev), flag, otyp, procp); + return (0); +} + +int +mydev_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, + struct thread *td) +{ + int error = 0; + struct proc *procp = td->td_proc; + + printf("mydev_ioctl: dev_t=%lu, cmd=%lx, arg=%p, mode=%x procp=%p\n", + dev2udev(dev), cmd, arg, mode, procp); + + switch(cmd) { + case CDEV_IOCTL1: + printf("you called mydev_ioctl CDEV_IOCTL1\n"); + break; + default: + printf("No such ioctl for me!\n"); + error = EINVAL; + break; + } + return (error); +} + +/* + * mydev_write takes in a character string and saves it + * to buf for later accessing. + */ +int +mydev_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + int err = 0; + + printf("mydev_write: dev_t=%lu, uio=%p, ioflag=%d\n", + dev2udev(dev), uio, ioflag); + + err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len); + if (err != 0) { + printf("Write to \"cdev\" failed.\n"); + } + return(err); +} + +/* + * The mydev_read function just takes the buf that was saved + * via mydev_write() and returns it to userland for + * accessing. + */ +int +mydev_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + int err = 0; + + printf("mydev_read: dev_t=%lu, uio=%p, ioflag=%d\n", + dev2udev(dev), uio, ioflag); + + if (len <= 0) { + err = -1; + } else { /* copy buf to userland */ + copystr(&buf, uio->uio_iov->iov_base, 513, &len); + } + return(err); +} diff --git a/share/examples/kld/cdev/module/cdev.h b/share/examples/kld/cdev/module/cdev.h new file mode 100644 index 000000000000..0ce0dd14d359 --- /dev/null +++ b/share/examples/kld/cdev/module/cdev.h @@ -0,0 +1,81 @@ +/* 08 Nov 1998*/ +/*- + * cdev.h - header for sample kld module implementing a character device + * driver. + * + * 08 Nov 1998 Rajesh Vaidheeswarran + * + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1998 Rajesh Vaidheeswarran + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Rajesh Vaidheeswarran. + * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1993 Terrence R. Lambert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef __CDEV_H_ +#define __CDEV_H_ + +d_open_t mydev_open; +d_close_t mydev_close; +d_ioctl_t mydev_ioctl; +d_read_t mydev_read; +d_write_t mydev_write; + +#endif diff --git a/share/examples/kld/cdev/module/cdevmod.c b/share/examples/kld/cdev/module/cdevmod.c new file mode 100644 index 000000000000..1df008ac017b --- /dev/null +++ b/share/examples/kld/cdev/module/cdevmod.c @@ -0,0 +1,146 @@ +/* 08 Nov 1998*/ +/*- + * cdevmod.c - a sample kld module implementing a character device driver. + * + * 08 Nov 1998 Rajesh Vaidheeswarran + * + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1998 Rajesh Vaidheeswarran + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Rajesh Vaidheeswarran. + * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1993 Terrence R. Lambert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> + +#include "cdev.h" + +static struct cdevsw my_devsw = { + /* version */ .d_version = D_VERSION, + /* open */ .d_open = mydev_open, + /* close */ .d_close = mydev_close, + /* read */ .d_read = mydev_read, + /* write */ .d_write = mydev_write, + /* ioctl */ .d_ioctl = mydev_ioctl, + /* name */ .d_name = "cdev" +}; + +/* + * Used as the variable that is the reference to our device + * in devfs... we must keep this variable sane until we + * call kldunload. + */ +static struct cdev *sdev; + +/* + * This function is called each time the module is loaded or unloaded. + * Since we are a miscellaneous module, we have to provide whatever + * code is necessary to patch ourselves into the area we are being + * loaded to change. + * + * The stat information is basically common to all modules, so there + * is no real issue involved with stat; we will leave it lkm_nullcmd(), + * since we don't have to do anything about it. + */ + +static int +cdev_load(module_t mod, int cmd, void *arg) +{ + int err = 0; + struct make_dev_args mda; + + switch (cmd) { + case MOD_LOAD: + + /* Do any initialization that you should do with the kernel */ + + /* if we make it to here, print copyright on console*/ + printf("\nSample Loaded kld character device driver\n"); + printf("Copyright (c) 1998\n"); + printf("Rajesh Vaidheeswarran\n"); + printf("All rights reserved\n"); + + make_dev_args_init(&mda); + mda.mda_devsw = &my_devsw; + mda.mda_uid = UID_ROOT; + mda.mda_gid = GID_WHEEL; + mda.mda_mode = 0600; + err = make_dev_s(&mda, &sdev, "cdev"); + break; + + case MOD_UNLOAD: + printf("Unloaded kld character device driver\n"); + destroy_dev(sdev); + break; /* Success*/ + + default: /* we only understand load/unload*/ + err = EOPNOTSUPP; + break; + } + + return(err); +} + +/* Now declare the module to the system */ + +DEV_MODULE(cdev, cdev_load, NULL); diff --git a/share/examples/kld/cdev/test/Makefile b/share/examples/kld/cdev/test/Makefile new file mode 100644 index 000000000000..3ac6e07d339f --- /dev/null +++ b/share/examples/kld/cdev/test/Makefile @@ -0,0 +1,96 @@ +# 05 Jun 93 +# +# Makefile for testmisc +# +# 05 Jun 93 Rajesh Vaidheeswarran Original +# +# Copyright (c) 1993 Rajesh Vaidheeswarran. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Rajesh Vaidheeswarran. +# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Copyright (c) 1993 Terrence R. Lambert. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by Terrence R. Lambert. +# 4. The name Terrence R. Lambert may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/cdev/test +PROG= testcdev +MAN= +WARNS?= 5 + +MODSTAT= /sbin/kldstat + +load: + @echo "This test program will call the sample kld character device "; + @echo "driver." + @echo + @echo "The sample driver will display a message on the" + @echo "system console each time an ioctl is sent to it." + @echo + @echo + @echo + @./testcdev + +unload: + @echo "This test program will cause an error if the driver" + @echo "has been successfully unloaded by building 'unload' in" + @echo "the 'module' subdirectory." + @echo + ${MODSTAT} -n cdev + +install: + +.include <bsd.prog.mk> diff --git a/share/examples/kld/cdev/test/testcdev.c b/share/examples/kld/cdev/test/testcdev.c new file mode 100644 index 000000000000..55205ac9b73e --- /dev/null +++ b/share/examples/kld/cdev/test/testcdev.c @@ -0,0 +1,125 @@ +/* 08 Nov 1998*/ +/*- + * testmisc.c + * + * Test program to call the sample loaded kld device driver. + * + * 05 Jun 93 Rajesh Vaidheeswarran Original + * + * + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (c) 1993 Rajesh Vaidheeswarran. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Rajesh Vaidheeswarran. + * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE RAJESH VAIDHEESWARRAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (c) 1993 Terrence R. Lambert. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Terrence R. Lambert. + * 4. The name Terrence R. Lambert may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include <sys/types.h> +#include <sys/ioccom.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <paths.h> +#include <string.h> +#include <unistd.h> + +#define CDEV_IOCTL1 _IOR('C', 1, u_int) +#define CDEV_DEVICE "cdev" + +static char writestr[] = "Hello kernel!"; +static char buf[512+1]; + +int +main(int argc __unused, char *argv[] __unused) +{ + int kernel_fd; + int one; + int len; + + if ((kernel_fd = open("/dev/" CDEV_DEVICE, O_RDWR)) == -1) { + perror("/dev/" CDEV_DEVICE); + exit(1); + } + + /* Send ioctl */ + if (ioctl(kernel_fd, CDEV_IOCTL1, &one) == -1) { + perror("CDEV_IOCTL1"); + } else { + printf( "Sent ioctl CDEV_IOCTL1 to device %s%s\n", _PATH_DEV, CDEV_DEVICE); + } + + len = strlen(writestr) + 1; + + /* Write operation */ + if (write(kernel_fd, writestr, len) == -1) { + perror("write()"); + } else { + printf("Written \"%s\" string to device /dev/" CDEV_DEVICE "\n", writestr); + } + + /* Read operation */ + if (read(kernel_fd, buf, len) == -1) { + perror("read()"); + } else { + printf("Read \"%s\" string from device /dev/" CDEV_DEVICE "\n", buf); + } + + exit(0); +} diff --git a/share/examples/kld/dyn_sysctl/Makefile b/share/examples/kld/dyn_sysctl/Makefile new file mode 100644 index 000000000000..0dffd9c8e7b0 --- /dev/null +++ b/share/examples/kld/dyn_sysctl/Makefile @@ -0,0 +1,7 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/${KMOD} +SRCS = dyn_sysctl.c +KMOD = dyn_sysctl + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/dyn_sysctl/README b/share/examples/kld/dyn_sysctl/README new file mode 100644 index 000000000000..054a6e2328f7 --- /dev/null +++ b/share/examples/kld/dyn_sysctl/README @@ -0,0 +1,6 @@ +This example module creates partially overlapping subtrees to demonstrate +reference counting. It also contains example of attaching a subtree to the +wrong place, i.e. to a dynamic oid that could belong to someone else. +The framework should deal with this case gracefully. + +Andrzej Bialecki <abial@freebsd.org> diff --git a/share/examples/kld/dyn_sysctl/dyn_sysctl.c b/share/examples/kld/dyn_sysctl/dyn_sysctl.c new file mode 100644 index 000000000000..b6d390bb9583 --- /dev/null +++ b/share/examples/kld/dyn_sysctl/dyn_sysctl.c @@ -0,0 +1,167 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 Andrzej Bialecki <abial@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/module.h> +#include <sys/sysctl.h> +#include <sys/kernel.h> + + +/* Some example data */ +static long a = 100; +static int b = 200; +static char *c = "hi there from dyn_sysctl"; +static struct sysctl_oid *a_root, *a_root1, *b_root; +static struct sysctl_ctx_list clist, clist1, clist2; + +static int +sysctl_dyn_sysctl_test(SYSCTL_HANDLER_ARGS) +{ + char *buf = "let's produce some text..."; + + return (sysctl_handle_string(oidp, buf, strlen(buf), req)); +} + +/* + * The function called at load/unload. + */ +static int +load(module_t mod, int cmd, void *arg) +{ + int error; + + error = 0; + switch (cmd) { + case MOD_LOAD: + /* Initialize the contexts */ + printf("Initializing contexts and creating subtrees.\n\n"); + sysctl_ctx_init(&clist); + sysctl_ctx_init(&clist1); + sysctl_ctx_init(&clist2); + /* + * Create two partially overlapping subtrees, belonging + * to different contexts. + */ + printf("TREE ROOT NAME\n"); + a_root = SYSCTL_ADD_ROOT_NODE(&clist, + OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0, + "dyn_sysctl root node"); + a_root = SYSCTL_ADD_ROOT_NODE(&clist1, + OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0, + "dyn_sysctl root node"); + if (a_root == NULL) { + printf("SYSCTL_ADD_NODE failed!\n"); + return (EINVAL); + } + SYSCTL_ADD_LONG(&clist, SYSCTL_CHILDREN(a_root), + OID_AUTO, "long_a", CTLFLAG_RW, &a, "just to try"); + SYSCTL_ADD_INT(&clist, SYSCTL_CHILDREN(a_root), + OID_AUTO, "int_b", CTLFLAG_RW, &b, 0, "just to try 1"); + a_root1 = SYSCTL_ADD_NODE(&clist, SYSCTL_CHILDREN(a_root), + OID_AUTO, "nextlevel", CTLFLAG_RD, 0, "one level down"); + SYSCTL_ADD_STRING(&clist, SYSCTL_CHILDREN(a_root1), + OID_AUTO, "string_c", CTLFLAG_RD, c, 0, "just to try 2"); + printf("1. (%p) / dyn_sysctl\n", &clist); + + /* Add a subtree under already existing category */ + a_root1 = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(_kern), + OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0, "dyn_sysctl root node"); + if (a_root1 == NULL) { + printf("SYSCTL_ADD_NODE failed!\n"); + return (EINVAL); + } + SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(a_root1), + OID_AUTO, "procedure", CTLTYPE_STRING | CTLFLAG_RD, + NULL, 0, sysctl_dyn_sysctl_test, "A", + "I can be here, too"); + printf(" (%p) /kern dyn_sysctl\n", &clist); + + /* Overlap second tree with the first. */ + b_root = SYSCTL_ADD_NODE(&clist1, SYSCTL_CHILDREN(a_root), + OID_AUTO, "nextlevel", CTLFLAG_RD, 0, "one level down"); + SYSCTL_ADD_STRING(&clist1, SYSCTL_CHILDREN(b_root), + OID_AUTO, "string_c1", CTLFLAG_RD, c, 0, "just to try 2"); + printf("2. (%p) / dyn_sysctl (overlapping #1)\n", &clist1); + + /* + * And now do something stupid. Connect another subtree to + * dynamic oid. + * WARNING: this is an example of WRONG use of dynamic sysctls. + */ + b_root=SYSCTL_ADD_NODE(&clist2, SYSCTL_CHILDREN(a_root1), + OID_AUTO, "bad", CTLFLAG_RW, 0, "dependent node"); + SYSCTL_ADD_STRING(&clist2, SYSCTL_CHILDREN(b_root), + OID_AUTO, "string_c", CTLFLAG_RD, c, 0, "shouldn't panic"); + printf("3. (%p) /kern/dyn_sysctl bad (WRONG!)\n", &clist2); + break; + case MOD_UNLOAD: + printf("1. Try to free ctx1 (%p): ", &clist); + if (sysctl_ctx_free(&clist) != 0) + printf("failed: expected. Need to remove ctx3 first.\n"); + else + printf("HELP! sysctl_ctx_free(%p) succeeded. EXPECT PANIC!!!\n", &clist); + printf("2. Try to free ctx3 (%p): ", &clist2); + if (sysctl_ctx_free(&clist2) != 0) { + printf("sysctl_ctx_free(%p) failed!\n", &clist2); + /* Remove subtree forcefully... */ + sysctl_remove_oid(b_root, 1, 1); + printf("sysctl_remove_oid(%p) succeeded\n", b_root); + } else + printf("Ok\n"); + printf("3. Try to free ctx1 (%p) again: ", &clist); + if (sysctl_ctx_free(&clist) != 0) { + printf("sysctl_ctx_free(%p) failed!\n", &clist); + /* Remove subtree forcefully... */ + sysctl_remove_oid(a_root1, 1, 1); + printf("sysctl_remove_oid(%p) succeeded\n", a_root1); + } else + printf("Ok\n"); + printf("4. Try to free ctx2 (%p): ", &clist1); + if (sysctl_ctx_free(&clist1) != 0) { + printf("sysctl_ctx_free(%p) failed!\n", &clist1); + /* Remove subtree forcefully... */ + sysctl_remove_oid(a_root, 1, 1); + } else + printf("Ok\n"); + break; + default: + error = EOPNOTSUPP; + break; + } + return (error); +} + +static moduledata_t mod_data = { + "dyn_sysctl", + load, + 0 +}; + +DECLARE_MODULE(dyn_sysctl, mod_data, SI_SUB_EXEC, SI_ORDER_ANY); diff --git a/share/examples/kld/firmware/Makefile b/share/examples/kld/firmware/Makefile new file mode 100644 index 000000000000..b4b144a7669d --- /dev/null +++ b/share/examples/kld/firmware/Makefile @@ -0,0 +1,6 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/firmware +SUBDIR= fwimage fwconsumer + +.include <bsd.subdir.mk> diff --git a/share/examples/kld/firmware/README b/share/examples/kld/firmware/README new file mode 100644 index 000000000000..473245a8e2ae --- /dev/null +++ b/share/examples/kld/firmware/README @@ -0,0 +1,17 @@ + +This is a simple example of the firmware(9) system. It consists of two +parts: + +1) fwimage + This is the firmware image (the ascii art of beastie from the boot + menu). The Makefile lists the firmware file "firmware.img" and the + short handle for this firmware image "beastie". + Note that the module is called "beastie" as well so that it can be + loaded automatically if requested. + +2) fwconsumer + This module tries to get the a firmware image called "beastie", + checks if the data is '\0'-terminated and prints it to the console. + It keeps a reference to the firmware until it is unloaded. + +This is mainly to demonstrate how to construct firmware image modules. diff --git a/share/examples/kld/firmware/fwconsumer/Makefile b/share/examples/kld/firmware/fwconsumer/Makefile new file mode 100644 index 000000000000..b29684999124 --- /dev/null +++ b/share/examples/kld/firmware/fwconsumer/Makefile @@ -0,0 +1,7 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/fwconsumer +KMOD= fw_consumer +SRCS= fw_consumer.c + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/firmware/fwconsumer/fw_consumer.c b/share/examples/kld/firmware/fwconsumer/fw_consumer.c new file mode 100644 index 000000000000..8d749fed65df --- /dev/null +++ b/share/examples/kld/firmware/fwconsumer/fw_consumer.c @@ -0,0 +1,77 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2006, Max Laier <mlaier@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/systm.h> +#include <sys/linker.h> +#include <sys/firmware.h> +#include <sys/proc.h> +#include <sys/module.h> + +static const struct firmware *fp; + +static int +fw_consumer_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + fp = firmware_get("beastie"); + + if (fp == NULL) + return (ENOENT); + + if (((const char *)fp->data)[fp->datasize - 1] != '\0') { + firmware_put(fp, FIRMWARE_UNLOAD); + return (EINVAL); + } + printf("%s", (const char *)fp->data); + + return (0); + case MOD_UNLOAD: + printf("Bye!\n"); + + if (fp != NULL) { + printf("%s", (const char *)fp->data); + firmware_put(fp, FIRMWARE_UNLOAD); + } + + return (0); + } + return (EINVAL); +} + +static moduledata_t fw_consumer_mod = { + "fw_consumer", + fw_consumer_modevent, + 0 +}; +DECLARE_MODULE(fw_consumer, fw_consumer_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); +MODULE_VERSION(fw_consumer, 1); +MODULE_DEPEND(fw_consumer, firmware, 1, 1, 1); diff --git a/share/examples/kld/firmware/fwimage/Makefile b/share/examples/kld/firmware/fwimage/Makefile new file mode 100644 index 000000000000..1e0e3ff3ca93 --- /dev/null +++ b/share/examples/kld/firmware/fwimage/Makefile @@ -0,0 +1,12 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/fwimage +KMOD= beastie +FIRMWS= firmware.img:beastie + +CLEANFILES= firmware.img + +firmware.img: firmware.img.uu + uudecode -p ${.ALLSRC} > ${.TARGET} + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/firmware/fwimage/firmware.img.uu b/share/examples/kld/firmware/fwimage/firmware.img.uu new file mode 100644 index 000000000000..075877e0bcb3 --- /dev/null +++ b/share/examples/kld/firmware/fwimage/firmware.img.uu @@ -0,0 +1,15 @@ +begin 644 firmware.img +M("`@("`@("`@("`@("`L("`@("`@("`L"B`@("`@("`@("`@("`O*"`@("`@ +M("`@*0H@("`@("`@("`@("`@7"!<7U]?("`@+R!\"B`@("`@("`@("`@("`O +M+2!?("`M+R`@)PH@("`@("`@("`@("`H+UPO(%P@7"`@("]<"B`@("`@("`@ +M("`@("\@+R`@('P@("`@(%P*("`@("`@("`@("`@3R!/("`@*2`O("`@('P* +M("`@("`@("`@("`@+5XM+2<\("`@("`G"B`@("`@("`@("`@*%\N*2`@7R`@ +M*2`@("\*("`@("`@("`@("`@+E]?7R\@("`@+PH@("`@("`@("`@("`@("TM +M+2TM)R`O"B`\+2TM+2X@("`@(%]?("\@7U\@("!<"B`\+2TM+7P]/3T]3RDI +M*3T]*2!<*2`O/3T]/0H@/"TM+2TG("`@("TM)R`N7U\L)R!<"B`@("`@("`@ +M("`@("`@?"`@("`@("`@?`H@("`@("`@("`@("`@("!<("`@("`@("\@("`@ +M("`@+UP*("`@("`@("`@(%]?7U]?7R@@*%\@("\@7%]?7U]?7R\*("`@("`@ +M("`L)R`@+"TM+2TM)R`@('P*("`@("`@("`M+7M?7U]?7U]?7U]?*2`@0V]P +@>7)I9VAT("AC*2`R,#`S(%-C;W1T($QO;F<*```````` +` +end diff --git a/share/examples/kld/khelp/Makefile b/share/examples/kld/khelp/Makefile new file mode 100644 index 000000000000..7cbaa79ceda6 --- /dev/null +++ b/share/examples/kld/khelp/Makefile @@ -0,0 +1,12 @@ + +.include <bsd.own.mk> + +# Change if the src tree you are compiling for is not in /usr/src +#SYSDIR=/usr/src/sys + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/khelp +KMOD= h_example +SRCS= h_example.c + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/khelp/README b/share/examples/kld/khelp/README new file mode 100644 index 000000000000..af201809864c --- /dev/null +++ b/share/examples/kld/khelp/README @@ -0,0 +1,5 @@ + +An example Khelp module which uses the helper hook points available in the TCP +stack to calculate a per-connection count of inbound and outbound packets when +the connection is in the established state. The code is verbosely documented in +an attempt to explain how everything fits together. diff --git a/share/examples/kld/khelp/h_example.c b/share/examples/kld/khelp/h_example.c new file mode 100644 index 000000000000..fea7826a1fb4 --- /dev/null +++ b/share/examples/kld/khelp/h_example.c @@ -0,0 +1,153 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010-2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University of Technology, Melbourne, Australia by + * Lawrence Stewart under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This example Khelp module uses the helper hook points available in the TCP + * stack to calculate a per-connection count of inbound and outbound packets + * when the connection is in the established state. The code is verbosely + * documented in an attempt to explain how everything fits together. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/hhook.h> +#include <sys/khelp.h> +#include <sys/module.h> +#include <sys/module_khelp.h> +#include <sys/socket.h> +#include <sys/socketvar.h> + +#include <netinet/tcp_var.h> + +#include <vm/uma.h> + +/* + * Function prototype for our helper hook (man 9 hhook) compatible hook + * function. + */ +static int example_hook(int hhook_type, int hhook_id, void *udata, + void *ctx_data, void *hdata, struct osd *hosd); + +/* + * Our per-connection persistent data storage struct. + */ +struct example { + uint32_t est_in_count; + uint32_t est_out_count; +}; + +/* + * Fill in the required bits of our module's struct helper (defined in + * <sys/module_khelp.h>). + * + * - Our helper will be storing persistent state for each TCP connection, so we + * request the use the Object Specific Data (OSD) feature from the framework by + * setting the HELPER_NEEDS_OSD flag. + * + * - Our helper is related to the TCP subsystem, so tell the Khelp framework + * this by setting an appropriate class for the module. When a new TCP + * connection is created, the Khelp framework takes care of associating helper + * modules of the appropriate class with the new connection. + */ +struct helper example_helper = { + .h_flags = HELPER_NEEDS_OSD, + .h_classes = HELPER_CLASS_TCP +}; + +/* + * Set which helper hook points our module wants to hook by creating an array of + * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established + * inbound/outbound hook points (TCP hhook points are defined in + * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user + * data pointer to be passed to our hook function when called, so we set it to + * NULL. + */ +struct hookinfo example_hooks[] = { + { + .hook_type = HHOOK_TYPE_TCP, + .hook_id = HHOOK_TCP_EST_IN, + .hook_udata = NULL, + .hook_func = &example_hook + }, + { + .hook_type = HHOOK_TYPE_TCP, + .hook_id = HHOOK_TCP_EST_OUT, + .hook_udata = NULL, + .hook_func = &example_hook + } +}; + +/* + * Very simple helper hook function. Here's a quick run through the arguments: + * + * - hhook_type and hhook_id are useful if you use a single function with many + * hook points and want to know which hook point called the function. + * + * - udata will be NULL, because we didn't elect to pass a pointer in either of + * the hookinfo structs we instantiated above in the example_hooks array. + * + * - ctx_data contains context specific data from the hook point call site. The + * data type passed is subsystem dependent. In the case of TCP, the hook points + * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>). + * + * - hdata is a pointer to the persistent per-object storage for our module. The + * pointer is allocated automagically by the Khelp framework when the connection + * is created, and comes from a dedicated UMA zone. It will never be NULL. + * + * - hosd can be used with the Khelp framework's khelp_get_osd() function to + * access data belonging to a different Khelp module. + */ +static int +example_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data, + void *hdata, struct osd *hosd) +{ + struct example *data; + + data = hdata; + + if (hhook_id == HHOOK_TCP_EST_IN) + data->est_in_count++; + else if (hhook_id == HHOOK_TCP_EST_OUT) + data->est_out_count++; + + return (0); +} + +/* + * We use a convenient macro which handles registering our module with the Khelp + * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e. + * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA() + * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD() + * macro instead. + */ +KHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1, + sizeof(struct example), NULL, NULL); diff --git a/share/examples/kld/random_adaptor/Makefile b/share/examples/kld/random_adaptor/Makefile new file mode 100644 index 000000000000..c391da795e89 --- /dev/null +++ b/share/examples/kld/random_adaptor/Makefile @@ -0,0 +1,7 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/${KMOD} +KMOD= random_adaptor_example +SRCS= ${KMOD}.c + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c new file mode 100644 index 000000000000..6dd3321d1286 --- /dev/null +++ b/share/examples/kld/random_adaptor/random_adaptor_example.c @@ -0,0 +1,124 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/random.h> +#include <sys/systm.h> + +#include <dev/random/randomdev.h> +#include <dev/random/randomdev_soft.h> +#include <dev/random/random_adaptors.h> +#include <dev/random/live_entropy_sources.h> + +static void live_random_example_init(void); +static void live_random_example_deinit(void); +static u_int live_random_example_read(void *, u_int); + +struct random_adaptor live_random_example = { + .les_ident = "Example RNG", + .les_source = RANDOM_PURE_BOGUS, /* Make sure this is in + * sys/random.h and is unique */ + .les_read = live_random_example_read, +}; + +/* + * Used under the license provided @ http://xkcd.com/221/ + * http://creativecommons.org/licenses/by-nc/2.5/ + */ +static uint8_t +getRandomNumber(void) +{ + return 4; /* chosen by fair dice roll, guaranteed to be random */ +} + +static void +live_random_example_init(void) +{ + + /* Do initialisation stuff here */ +} + +static void +live_random_example_deinit(void) +{ + + /* Do de-initialisation stuff here */ +} + +/* get <c> bytes of random stuff into <buf>. You may presume + * that <c> is a multiple of 2^n, with n>=3. A typical value + * is c=16. + */ +static u_int +live_random_example_read(void *buf, u_int c) +{ + uint8_t *b; + int count; + + b = buf; + + for (count = 0; count < c; count++) + b[count] = getRandomNumber(); + + /* printf("returning %d bytes of pure randomness\n", c); */ + return (c); +} + +/* ARGSUSED */ +static int +live_random_example_modevent(module_t mod __unused, int type, void *unused __unused) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + live_entropy_source_register(&live_random_example); + break; + + case MOD_UNLOAD: + live_entropy_source_deregister(&live_random_example); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + } + + return (error); +} + +DEV_MODULE(live_random_example, live_random_example_modevent, NULL); +MODULE_VERSION(live_random_example, 1); +MODULE_DEPEND(live_random_example, randomdev, 1, 1, 1); diff --git a/share/examples/kld/syscall/Makefile b/share/examples/kld/syscall/Makefile new file mode 100644 index 000000000000..efae887771e2 --- /dev/null +++ b/share/examples/kld/syscall/Makefile @@ -0,0 +1,8 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/syscall +SUBDIR= module test + +load unload: _SUBDIR + +.include <bsd.subdir.mk> diff --git a/share/examples/kld/syscall/module/Makefile b/share/examples/kld/syscall/module/Makefile new file mode 100644 index 000000000000..760825e4d52a --- /dev/null +++ b/share/examples/kld/syscall/module/Makefile @@ -0,0 +1,8 @@ +# Makefile for building the sample syscall module + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/${KMOD} +KMOD= syscall +SRCS= syscall.c + +.include <bsd.kmod.mk> diff --git a/share/examples/kld/syscall/module/syscall.c b/share/examples/kld/syscall/module/syscall.c new file mode 100644 index 000000000000..3f6051d03777 --- /dev/null +++ b/share/examples/kld/syscall/module/syscall.c @@ -0,0 +1,83 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Assar Westerlund + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/module.h> +#include <sys/sysproto.h> +#include <sys/sysent.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +/* + * The function for implementing the syscall. + */ +static int +hello(struct thread *td, void *arg) +{ + + printf("hello kernel\n"); + return (0); +} + +/* + * The `sysent' for the new syscall + */ +static struct sysent hello_sysent = { + .sy_narg = 0, + .sy_call = hello +}; + +/* + * The offset in sysent where the syscall is allocated. + */ +static int offset = NO_SYSCALL; + +/* + * The function called at load/unload. + */ +static int +load(struct module *module, int cmd, void *arg) +{ + int error = 0; + + switch (cmd) { + case MOD_LOAD : + printf("syscall loaded at %d\n", offset); + break; + case MOD_UNLOAD : + printf("syscall unloaded from %d\n", offset); + break; + default : + error = EOPNOTSUPP; + break; + } + return (error); +} + +SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL); diff --git a/share/examples/kld/syscall/test/Makefile b/share/examples/kld/syscall/test/Makefile new file mode 100644 index 000000000000..d14cd895c15d --- /dev/null +++ b/share/examples/kld/syscall/test/Makefile @@ -0,0 +1,9 @@ +# Makefile for simple caller of syscall + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/kld/test +PROG= call +MAN= +WARNS?= 5 + +.include <bsd.prog.mk> diff --git a/share/examples/kld/syscall/test/call.c b/share/examples/kld/syscall/test/call.c new file mode 100644 index 000000000000..e62f8f27f1dd --- /dev/null +++ b/share/examples/kld/syscall/test/call.c @@ -0,0 +1,51 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1999 Assar Westerlund + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/module.h> +#include <sys/syscall.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(int argc __unused, char **argv __unused) +{ + int modid, syscall_num; + struct module_stat stat; + + stat.version = sizeof(stat); + if ((modid = modfind("sys/syscall")) == -1) + err(1, "modfind"); + if (modstat(modid, &stat) != 0) + err(1, "modstat"); + syscall_num = stat.data.intval; + return syscall (syscall_num); +} diff --git a/share/examples/libifconfig/Makefile b/share/examples/libifconfig/Makefile new file mode 100644 index 000000000000..954206116eaa --- /dev/null +++ b/share/examples/libifconfig/Makefile @@ -0,0 +1,10 @@ +default: + $(CC) -Wall -fPIC -lifconfig -g -o example_setdescription setdescription.c + $(CC) -Wall -fPIC -lifconfig -g -o example_setmtu setmtu.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifdestroy ifdestroy.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifcreate ifcreate.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifcreatevlan ifcreatevlan.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifchanagevlan ifchanagevlan.c + $(CC) -Wall -fPIC -lifconfig -g -o example_status status.c +clean: + rm -f example_* diff --git a/share/examples/libifconfig/ifchangevlan.c b/share/examples/libifconfig/ifchangevlan.c new file mode 100644 index 000000000000..18a7b6de638a --- /dev/null +++ b/share/examples/libifconfig/ifchangevlan.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + +#include <net/if_vlan_var.h> + +int +main(int argc, char *argv[]) +{ + char *ifname, *parentif; + unsigned short vlantag; + const char *errstr; + ifconfig_handle_t *lifh; + + if (argc != 4) { + errx(EINVAL, "Invalid number of arguments." + " Should provide exactly three arguments: " + "INTERFACE, PARENT_INTERFACE and VLAN_TAG."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + parentif = strdup(argv[2]); + vlantag = strtonum(argv[3], 0, USHRT_MAX, &errstr); + + if (errstr != NULL) { + errx(1, "VLAN_TAG must be between 0 and %i.\n", USHRT_MAX); + } + + printf("Interface: %s\nNew VLAN tag: %i\n", ifname, vlantag); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_set_vlantag(lifh, ifname, parentif, vlantag) == 0) { + printf("Successfully changed vlan tag.\n"); + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + free(parentif); + return (0); + } + + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (ifconfig_err_ioctlreq(lifh) == SIOCGETVLAN) { + warnx("Target interface isn't a VLAN interface.\n"); + } + if (ifconfig_err_ioctlreq(lifh) == SIOCSETVLAN) { + warnx( + "Couldn't change VLAN properties of interface.\n"); + } + break; + default: + warnx( + "This is a thorough example accommodating for temporary" + " 'not implemented yet' errors. That's likely what happened" + " now. If not, your guess is as good as mine. ;)" + " Error code: %d\n", ifconfig_err_errno( + lifh)); + break; + } + + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + free(parentif); + return (-1); +} diff --git a/share/examples/libifconfig/ifcreate.c b/share/examples/libifconfig/ifcreate.c new file mode 100644 index 000000000000..ae1e565d2ab7 --- /dev/null +++ b/share/examples/libifconfig/ifcreate.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016-2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + + +int +main(int argc, char *argv[]) +{ + char *ifname, *ifactualname; + ifconfig_handle_t *lifh; + + if (argc != 2) { + errx(EINVAL, "Invalid number of arguments." + " Only one argument is accepted, and it should be the name" + " of the interface to be created."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + + printf("Requested interface name: %s\n", ifname); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_create_interface(lifh, ifname, &ifactualname) == 0) { + printf("Successfully created interface '%s'\n", ifactualname); + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + free(ifactualname); + return (0); + } + + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (ifconfig_err_ioctlreq(lifh) == SIOCIFCREATE2) { + warnx( + "Failed to create interface (SIOCIFCREATE2)\n"); + } + break; + default: + warnx( + "This is a thorough example accommodating for temporary" + " 'not implemented yet' errors. That's likely what happened" + " now. If not, your guess is as good as mine. ;)" + " Error code: %d\n", ifconfig_err_errno( + lifh)); + break; + } + + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + free(ifactualname); + return (-1); +} diff --git a/share/examples/libifconfig/ifcreatevlan.c b/share/examples/libifconfig/ifcreatevlan.c new file mode 100644 index 000000000000..b41dd63bfe82 --- /dev/null +++ b/share/examples/libifconfig/ifcreatevlan.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + + +int +main(int argc, char *argv[]) +{ + char *parentif, *ifactualname; + unsigned short vlantag; + const char *errstr; + ifconfig_handle_t *lifh; + + if (argc != 3) { + errx(EINVAL, "Invalid number of arguments." + " Should provide exactly two arguments: " + "PARENT_INTERFACE and VLAN_TAG."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + parentif = strdup(argv[1]); + vlantag = strtonum(argv[2], 0, USHRT_MAX, &errstr); + + if (errstr != NULL) { + errx(1, "VLAN_TAG must be between 0 and %i.\n", USHRT_MAX); + } + + printf("Parent interface: %s\nVLAN tag: %i\n", parentif, vlantag); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_create_interface_vlan(lifh, "vlan", &ifactualname, + parentif, vlantag) == 0) { + printf("Successfully created interface '%s'\n", ifactualname); + ifconfig_close(lifh); + lifh = NULL; + free(parentif); + free(ifactualname); + return (0); + } + + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (ifconfig_err_ioctlreq(lifh) == SIOCIFCREATE2) { + warnx( + "Failed to create interface (SIOCIFCREATE2)\n"); + } + break; + default: + warnx( + "This is a thorough example accommodating for temporary" + " 'not implemented yet' errors. That's likely what happened" + " now. If not, your guess is as good as mine. ;)" + " Error code: %d\n", ifconfig_err_errno( + lifh)); + break; + } + + ifconfig_close(lifh); + lifh = NULL; + free(parentif); + free(ifactualname); + return (-1); +} diff --git a/share/examples/libifconfig/ifdestroy.c b/share/examples/libifconfig/ifdestroy.c new file mode 100644 index 000000000000..d4f3d3ac6e6f --- /dev/null +++ b/share/examples/libifconfig/ifdestroy.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016-2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + + +int +main(int argc, char *argv[]) +{ + char *ifname; + ifconfig_handle_t *lifh; + + if (argc != 2) { + errx(EINVAL, "Invalid number of arguments." + " Only one argument is accepted, and it should be the name" + " of the interface to be destroyed."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + + printf("Interface name: %s\n", ifname); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_destroy_interface(lifh, ifname) == 0) { + printf("Successfully destroyed interface '%s'.", ifname); + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + return (0); + } + + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (ifconfig_err_ioctlreq(lifh) == SIOCIFDESTROY) { + warnx( + "Failed to destroy interface (SIOCIFDESTROY)\n"); + } + break; + default: + warnx( + "Should basically never end up here in this example.\n"); + break; + } + + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + return (-1); +} diff --git a/share/examples/libifconfig/setdescription.c b/share/examples/libifconfig/setdescription.c new file mode 100644 index 000000000000..5fde440b4bee --- /dev/null +++ b/share/examples/libifconfig/setdescription.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arpa/inet.h> +#include <net/if.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + + +int +main(int argc, char *argv[]) +{ + char *ifname, *ifdescr, *curdescr; + ifconfig_handle_t *lifh; + + if (argc != 3) { + errx(EINVAL, "Invalid number of arguments." + " First argument should be interface name, second argument" + " should be the description to set."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + ifdescr = strdup(argv[2]); + curdescr = NULL; + + printf("Interface name: %s\n", ifname); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_get_description(lifh, ifname, &curdescr) == 0) { + printf("Old description: %s\n", curdescr); + } + + printf("New description: %s\n\n", ifdescr); + + if (ifconfig_set_description(lifh, ifname, ifdescr) == 0) { + printf("New description successfully set.\n"); + } else { + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + err(ifconfig_err_errno(lifh), "Socket error"); + break; + case IOCTL: + err(ifconfig_err_errno( + lifh), "IOCTL(%lu) error", + ifconfig_err_ioctlreq(lifh)); + break; + default: + err(ifconfig_err_errno(lifh), "Other error"); + break; + } + } + + free(ifname); + free(ifdescr); + free(curdescr); + ifname = NULL; + ifdescr = NULL; + curdescr = NULL; + + ifconfig_close(lifh); + return (0); +} diff --git a/share/examples/libifconfig/setmtu.c b/share/examples/libifconfig/setmtu.c new file mode 100644 index 000000000000..06417cb7fc5b --- /dev/null +++ b/share/examples/libifconfig/setmtu.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-2017, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <err.h> +#include <errno.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + + +int +main(int argc, char *argv[]) +{ + char *ifname, *ptr; + int mtu; + ifconfig_handle_t *lifh; + + if (argc != 3) { + errx(EINVAL, "Invalid number of arguments." + " First argument should be interface name, second argument" + " should be the MTU to set."); + } + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + mtu = (int)strtol(argv[2], &ptr, 10); + + printf("Interface name: %s\n", ifname); + printf("New MTU: %d", mtu); + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(ENOMEM, "Failed to open libifconfig handle."); + return (-1); + } + + if (ifconfig_set_mtu(lifh, ifname, mtu) == 0) { + printf("Successfully changed MTU of %s to %d\n", ifname, mtu); + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + return (0); + } + + switch (ifconfig_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (ifconfig_err_ioctlreq(lifh) == SIOCSIFMTU) { + warnx("Failed to set MTU (SIOCSIFMTU)\n"); + } else { + warnx( + "Failed to set MTU due to error in unexpected ioctl() call %lu. Error code: %i.\n", + ifconfig_err_ioctlreq(lifh), + ifconfig_err_errno(lifh)); + } + break; + default: + warnx( + "Should basically never end up here in this example.\n"); + break; + } + + ifconfig_close(lifh); + lifh = NULL; + free(ifname); + return (-1); +} diff --git a/share/examples/libifconfig/status.c b/share/examples/libifconfig/status.c new file mode 100644 index 000000000000..6f0eeb0b223b --- /dev/null +++ b/share/examples/libifconfig/status.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2017, Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <arpa/inet.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_lagg.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <netinet/in.h> +#include <netinet/ip_carp.h> +#include <netinet6/in6_var.h> +#include <netinet6/nd6.h> + +#include <err.h> +#include <errno.h> +#include <ifaddrs.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libifconfig.h> + +static const char *carp_states[] = { CARP_STATES }; + +static void +print_carp(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct carpreq carpr[CARP_MAXVHID]; + int i; + + if (ifconfig_carp_get_info(lifh, ifa->ifa_name, carpr, CARP_MAXVHID)) { + return; /* Probably not configured on this interface */ + } + for (i = 0; i < carpr[0].carpr_count; i++) { + printf("\tcarp: %s vhid %d advbase %d advskew %d", + carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid, + carpr[i].carpr_advbase, carpr[i].carpr_advskew); + printf("\n"); + } +} + +static void +print_inet4_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct ifconfig_inet_addr addr; + char addr_buf[NI_MAXHOST]; + + if (ifconfig_inet_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { + return; + } + + inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof(addr_buf)); + printf("\tinet %s", addr_buf); + + if (addr.dst) { + printf(" --> %s", inet_ntoa(addr.dst->sin_addr)); + } + + printf(" netmask 0x%x ", ntohl(addr.netmask->sin_addr.s_addr)); + + if ((addr.broadcast != NULL) && + (addr.broadcast->sin_addr.s_addr != 0)) { + printf("broadcast %s ", inet_ntoa(addr.broadcast->sin_addr)); + } + + if (addr.vhid != 0) { + printf("vhid %d ", addr.vhid); + } + printf("\n"); +} + +static void +print_inet6_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct ifconfig_inet6_addr addr; + char addr_buf[NI_MAXHOST]; + struct timespec now; + + /* Print the address */ + if (ifconfig_inet6_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) { + err(1, "ifconfig_inet6_get_addrinfo"); + } + if (0 != getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len, + addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST)) { + inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf, + sizeof(addr_buf)); + } + printf("\tinet6 %s", addr_buf); + + if (addr.dstin6) { + inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof(addr_buf)); + printf(" --> %s", addr_buf); + } + + /* Print the netmask */ + printf(" prefixlen %d ", addr.prefixlen); + + /* Print the scopeid*/ + if (addr.sin6->sin6_scope_id) { + printf("scopeid 0x%x ", addr.sin6->sin6_scope_id); + } + + /* Print the flags */ + if ((addr.flags & IN6_IFF_ANYCAST) != 0) { + printf("anycast "); + } + if ((addr.flags & IN6_IFF_TENTATIVE) != 0) { + printf("tentative "); + } + if ((addr.flags & IN6_IFF_DUPLICATED) != 0) { + printf("duplicated "); + } + if ((addr.flags & IN6_IFF_DETACHED) != 0) { + printf("detached "); + } + if ((addr.flags & IN6_IFF_DEPRECATED) != 0) { + printf("deprecated "); + } + if ((addr.flags & IN6_IFF_AUTOCONF) != 0) { + printf("autoconf "); + } + if ((addr.flags & IN6_IFF_TEMPORARY) != 0) { + printf("temporary "); + } + if ((addr.flags & IN6_IFF_PREFER_SOURCE) != 0) { + printf("prefer_source "); + } + + /* Print the lifetimes */ + clock_gettime(CLOCK_MONOTONIC_FAST, &now); + if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) { + printf("pltime "); + if (addr.lifetime.ia6t_preferred) { + printf("%ld ", MAX(0l, + addr.lifetime.ia6t_preferred - now.tv_sec)); + } else { + printf("infty "); + } + + printf("vltime "); + if (addr.lifetime.ia6t_expire) { + printf("%ld ", MAX(0l, + addr.lifetime.ia6t_expire - now.tv_sec)); + } else { + printf("infty "); + } + } + + /* Print the vhid */ + if (addr.vhid != 0) { + printf("vhid %d ", addr.vhid); + } + printf("\n"); +} + +static void +print_link_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + char addr_buf[NI_MAXHOST]; + struct sockaddr_dl *sdl; + int n; + + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + if ((sdl != NULL) && (sdl->sdl_alen > 0)) { + if (((sdl->sdl_type == IFT_ETHER) || + (sdl->sdl_type == IFT_L2VLAN) || + (sdl->sdl_type == IFT_BRIDGE)) && + (sdl->sdl_alen == ETHER_ADDR_LEN)) { + ether_ntoa_r((struct ether_addr *)LLADDR(sdl), + addr_buf); + printf("\tether %s\n", addr_buf); + } else { + n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; + + printf("\tlladdr %s\n", link_ntoa(sdl) + n); + } + } +} + +static void +print_ifaddr(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) +{ + switch (ifa->ifa_addr->sa_family) { + case AF_INET: + print_inet4_addr(lifh, ifa); + break; + case AF_INET6: + + /* + * printing AF_INET6 status requires calling SIOCGIFAFLAG_IN6 + * and SIOCGIFALIFETIME_IN6. TODO: figure out the best way to + * do that from within libifconfig + */ + print_inet6_addr(lifh, ifa); + break; + case AF_LINK: + print_link_addr(lifh, ifa); + break; + case AF_LOCAL: + case AF_UNSPEC: + default: + /* TODO */ + break; + } +} + +static void +print_nd6(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct in6_ndireq nd; + + if (ifconfig_get_nd6(lifh, ifa->ifa_name, &nd) == 0) { + printf("\tnd6 options=%x\n", nd.ndi.flags); + } else { + err(1, "Failed to get nd6 options"); + } +} + +static void +print_fib(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + int fib; + + if (ifconfig_get_fib(lifh, ifa->ifa_name, &fib) == 0) { + printf("\tfib: %d\n", fib); + } else { + err(1, "Failed to get interface FIB"); + } +} + +static void +print_lagg(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct lagg_protos lpr[] = LAGG_PROTOS; + struct ifconfig_lagg_status *ls; + struct lacp_opreq *lp; + const char *proto = "<unknown>"; + int i; + + if (ifconfig_lagg_get_lagg_status(lifh, ifa->ifa_name, &ls) < 0) { + if (ifconfig_err_errno(lifh) == EINVAL) { + return; + } + err(1, "Failed to get interface lagg status"); + } + + /* First print the proto */ + for (i = 0; i < nitems(lpr); i++) { + if (ls->ra->ra_proto == lpr[i].lpr_proto) { + proto = lpr[i].lpr_name; + break; + } + } + printf("\tlaggproto %s", proto); + + /* Now print the lagg hash */ + if (ls->rf->rf_flags & LAGG_F_HASHMASK) { + const char *sep = ""; + + printf(" lagghash "); + if (ls->rf->rf_flags & LAGG_F_HASHL2) { + printf("%sl2", sep); + sep = ","; + } + if (ls->rf->rf_flags & LAGG_F_HASHL3) { + printf("%sl3", sep); + sep = ","; + } + if (ls->rf->rf_flags & LAGG_F_HASHL4) { + printf("%sl4", sep); + sep = ","; + } + } + putchar('\n'); + printf("\tlagg options:\n"); + printf("\t\tflags=%x", ls->ro->ro_opts); + putchar('\n'); + printf("\t\tflowid_shift: %d\n", ls->ro->ro_flowid_shift); + if (ls->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) { + printf("\t\trr_limit: %d\n", ls->ro->ro_bkt); + } + printf("\tlagg statistics:\n"); + printf("\t\tactive ports: %d\n", ls->ro->ro_active); + printf("\t\tflapping: %u\n", ls->ro->ro_flapping); + for (i = 0; i < ls->ra->ra_ports; i++) { + lp = (struct lacp_opreq *)&ls->ra->ra_port[i].rp_lacpreq; + printf("\tlaggport: %s ", ls->ra->ra_port[i].rp_portname); + printf("flags=%x", ls->ra->ra_port[i].rp_flags); + if (ls->ra->ra_proto == LAGG_PROTO_LACP) { + printf(" state=%x", lp->actor_state); + } + putchar('\n'); + } + + printf("\n"); + ifconfig_lagg_free_lagg_status(ls); +} + +static void +print_laggport(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct lagg_reqport rp; + + if (ifconfig_lagg_get_laggport_status(lifh, ifa->ifa_name, &rp) < 0) { + if ((ifconfig_err_errno(lifh) == EINVAL) || + (ifconfig_err_errno(lifh) == ENOENT)) { + return; + } else { + err(1, "Failed to get lagg port status"); + } + } + + printf("\tlaggdev: %s\n", rp.rp_ifname); +} + +static void +print_groups(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + struct ifgroupreq ifgr; + struct ifg_req *ifg; + int len; + int cnt = 0; + + if (ifconfig_get_groups(lifh, ifa->ifa_name, &ifgr) != 0) { + err(1, "Failed to get groups"); + } + + ifg = ifgr.ifgr_groups; + len = ifgr.ifgr_len; + for (; ifg && len >= sizeof(struct ifg_req); ifg++) { + len -= sizeof(struct ifg_req); + if (strcmp(ifg->ifgrq_group, "all")) { + if (cnt == 0) { + printf("\tgroups: "); + } + cnt++; + printf("%s ", ifg->ifgrq_group); + } + } + if (cnt) { + printf("\n"); + } + + free(ifgr.ifgr_groups); +} + +static void +print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa) +{ + int i; + + /* Outline: + * 1) Determine whether the iface supports SIOGIFMEDIA or SIOGIFXMEDIA + * 2) Get the full media list + * 3) Print the current media word + * 4) Print the active media word, if different + * 5) Print the status + * 6) Print the supported media list + * + * How to print the media word: + * 1) Get the top-level interface type and description + * 2) Print the subtype + * 3) For current word only, print the top type, if it exists + * 4) Print options list + * 5) Print the instance, if there is one + * + * How to get the top-level interface type + * 1) Shift ifmw right by 0x20 and index into IFM_TYPE_DESCRIPTIONS + * + * How to get the top-level interface subtype + * 1) Shift ifmw right by 0x20, index into ifmedia_types_to_subtypes + * 2) Iterate through the resulting table's subtypes table, ignoring + * aliases. Iterate through the resulting ifmedia_description + * tables, finding an entry with the right media subtype + */ + struct ifmediareq *ifmr; + + if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) { + if (ifconfig_err_errtype(lifh) != OK) { + err(1, "Failed to get media info"); + } else { + return; /* Interface doesn't support media info */ + } + } + + printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current), + ifconfig_media_get_subtype(ifmr->ifm_current)); + if (ifmr->ifm_active != ifmr->ifm_current) { + const char **options; + + printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active)); + options = ifconfig_media_get_options(ifmr->ifm_active); + if (options != NULL && options[0] != NULL) { + printf(" <%s", options[0]); + for (size_t i = 1; options[i] != NULL; ++i) + printf(",%s", options[i]); + printf(">)\n"); + } else { + printf(")\n"); + } + free(options); + } else { + printf("\n"); + } + + if (ifmr->ifm_status & IFM_AVALID) { + printf("\tstatus: %s\n", + ifconfig_media_get_status(ifmr)); + } + + printf("\tsupported media:\n"); + for (i = 0; i < ifmr->ifm_count; i++) { + const char **options; + + printf("\t\tmedia %s", + ifconfig_media_get_subtype(ifmr->ifm_ulist[i])); + options = ifconfig_media_get_options(ifmr->ifm_ulist[i]); + if (options != NULL && options[0] != NULL) { + printf(" mediaopt %s", options[0]); + for (size_t i = 1; options[i] != NULL; ++i) + printf(",%s", options[i]); + printf("\n"); + } else { + printf("\n"); + } + free(options); + } + free(ifmr); +} + +static void +print_iface(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused) +{ + int metric, mtu; + char *description = NULL; + struct ifconfig_capabilities caps; + struct ifstat ifs; + + printf("%s: flags=%x ", ifa->ifa_name, ifa->ifa_flags); + + if (ifconfig_get_metric(lifh, ifa->ifa_name, &metric) == 0) { + printf("metric %d ", metric); + } else { + err(1, "Failed to get interface metric"); + } + + if (ifconfig_get_mtu(lifh, ifa->ifa_name, &mtu) == 0) { + printf("mtu %d\n", mtu); + } else { + err(1, "Failed to get interface MTU"); + } + + if (ifconfig_get_description(lifh, ifa->ifa_name, &description) == 0) { + printf("\tdescription: %s\n", description); + } + + if (ifconfig_get_capability(lifh, ifa->ifa_name, &caps) == 0) { + if (caps.curcap != 0) { + printf("\toptions=%x\n", caps.curcap); + } + if (caps.reqcap != 0) { + printf("\tcapabilities=%x\n", caps.reqcap); + } + } else { + err(1, "Failed to get interface capabilities"); + } + + ifconfig_foreach_ifaddr(lifh, ifa, print_ifaddr, NULL); + + /* This paragraph is equivalent to ifconfig's af_other_status funcs */ + print_nd6(lifh, ifa); + print_media(lifh, ifa); + print_groups(lifh, ifa); + print_fib(lifh, ifa); + print_carp(lifh, ifa); + print_lagg(lifh, ifa); + print_laggport(lifh, ifa); + + if (ifconfig_get_ifstatus(lifh, ifa->ifa_name, &ifs) == 0) { + printf("%s", ifs.ascii); + } + + free(description); +} + +int +main(int argc, char *argv[]) +{ + ifconfig_handle_t *lifh; + + if (argc != 1) { + errx(1, "Usage: example_status"); + } + + lifh = ifconfig_open(); + if (lifh == NULL) { + errx(1, "Failed to open libifconfig handle."); + } + + if (ifconfig_foreach_iface(lifh, print_iface, NULL) != 0) { + err(1, "Failed to get interfaces"); + } + + ifconfig_close(lifh); + lifh = NULL; + return (-1); +} diff --git a/share/examples/libusb20/Makefile b/share/examples/libusb20/Makefile new file mode 100644 index 000000000000..262f1ac3825a --- /dev/null +++ b/share/examples/libusb20/Makefile @@ -0,0 +1,16 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/libusb20 +TARGETS= bulk control +CFLAGS+= -Wall + +all: $(TARGETS) + +bulk: bulk.o util.o + $(CC) $(CFLAGS) -o bulk bulk.o util.o -lusb + +control: control.o util.o + $(CC) $(CFLAGS) -o control control.o util.o -lusb + +clean: + rm -f $(TARGETS) *.o *~ diff --git a/share/examples/libusb20/README b/share/examples/libusb20/README new file mode 100644 index 000000000000..a2c1510aae2b --- /dev/null +++ b/share/examples/libusb20/README @@ -0,0 +1,40 @@ +As I dug my own way through the documentation of libusb 2.0 that ships +with FreeBSD 8+ as the OS'es own USB library API, I noticed there are +only few code examples around under /usr/src (namely, usbconfig +itself). + +The libusb20(3) man page is a starting point, but it's a reference +manual, nothing less, nothing more. Using just a reference, it's not +very easy to start writing your own code based on that. + +So I started writing my own examples, to "get a feeling" about how to +use the library. I covered two typical scenarios which are common for +a number of devices. + +The first one is called "bulk", and uses bulk output (host to device) +and input transfers to talk to an USB device. + +The second one is called "control", and can use both control output +and input transfers, as well as so-called interrupt transfers. The +latter are used for data that are being reported frequently or +repeatedly, like position updates from a pointing device (mouse). +Despite of its name, the host has to poll devices for their interrupt +transfers on each USB frame (i.e., each 1 ms). + +Recommended reading is the USB 3.0 specification (the older 2.0 one +would do as well), to be found under + +http://www.usb.org/developers/docs/ + +as well as documents for individual USB device classes where +appropriate. + +Feel free to be liberal in the licensing of these examples: while the +beer-ware license mandates to keep the license notice, this only +applies to modifications of the original examples itself. For +copy&pasting (even a larger) piece of an example into your own work, I +won't imply you have to reproduce the beer-ware license text there. +Feel free to credit my name in your derived work if you want. + +Dresden, July 2012 +Joerg Wunsch <joerg@FreeBSD.org> diff --git a/share/examples/libusb20/bulk.c b/share/examples/libusb20/bulk.c new file mode 100644 index 000000000000..2f7588bd592f --- /dev/null +++ b/share/examples/libusb20/bulk.c @@ -0,0 +1,244 @@ +/*- + * SPDX-License-Identifier: Beerware + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): + * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + */ + +/* + * Simple demo program to illustrate the handling of FreeBSD's + * libusb20. + * + * Issues a bulk output, and then requests a bulk input. + */ + +/* + * Examples: + * Just list all VID:PID pairs + * ./bulk + * + * Say "hello" to an Atmel JTAGICEmkII. + * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97 + * + * Return the INQUIRY data of an USB mass storage device. + * (It's best to have the umass(4) driver unloaded while doing such + * experiments, and perform a "usbconfig reset" for the device if it + * gets stuck.) + * ./bulk -v 0x5e3 -p 0x723 -i 0x81 -o 2 0x55 0x53 0x42 0x43 1 2 3 4 31 12 0x80 0x24 0 0 0 0x12 0 0 0 36 0 0 0 0 0 0 0 0 0 0 + */ + + +#include <limits.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> + +#include <libusb20.h> +#include <libusb20_desc.h> + +#include "util.h" + +/* + * If you want to see the details of the internal datastructures + * in the debugger, unifdef the following. + */ +#ifdef DEBUG +# include <sys/queue.h> +# include "/usr/src/lib/libusb/libusb20_int.h" +#endif + +#define BUFLEN 64 + +#define TIMEOUT 5000 /* 5 s */ + +int in_ep, out_ep; /* endpoints */ +uint8_t out_buf[BUFLEN]; +uint16_t out_len; + +static void +doit(struct libusb20_device *dev) +{ + int rv; + + /* + * Open the device, allocating memory for two possible (bulk or + * interrupt) transfers. + * + * If only control transfers are intended (via + * libusb20_dev_request_sync()), transfer_max can be given as 0. + */ + if ((rv = libusb20_dev_open(dev, 2)) != 0) + { + fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv)); + return; + } + + /* + * If the device has more than one configuration, select the desired + * one here. + */ + if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0) + { + fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv)); + return; + } + + /* + * Two transfers have been requested in libusb20_dev_open() above; + * obtain the corresponding transfer struct pointers. + */ + struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0); + struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1); + + if (xfr_in == NULL || xfr_out == NULL) + { + fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv)); + return; + } + + /* + * Open both transfers, the "out" one for the write endpoint, the + * "in" one for the read endpoint (ep | 0x80). + */ + if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0) + { + fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); + return; + } + if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0) + { + fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); + return; + } + + uint8_t in_buf[BUFLEN]; + uint32_t rlen; + + if (out_len > 0) + { + if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT)) + != 0) + { + fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv)); + } + printf("sent %d bytes\n", rlen); + } + + if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT)) + != 0) + { + fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv)); + } + printf("received %d bytes\n", rlen); + if (rlen > 0) + print_formatted(in_buf, rlen); + + libusb20_tr_close(xfr_out); + libusb20_tr_close(xfr_in); + + libusb20_dev_close(dev); +} + +static void +usage(void) +{ + fprintf(stderr, + "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]"); + exit(EX_USAGE); +} + +int +main(int argc, char **argv) +{ + unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */ + int c; + + while ((c = getopt(argc, argv, "i:o:p:v:")) != -1) + switch (c) + { + case 'i': + in_ep = strtol(optarg, NULL, 0); + break; + + case 'o': + out_ep = strtol(optarg, NULL, 0); + break; + + case 'p': + pid = strtol(optarg, NULL, 0); + break; + + case 'v': + vid = strtol(optarg, NULL, 0); + break; + + default: + usage(); + break; + } + argc -= optind; + argv += optind; + + if (vid != UINT_MAX || pid != UINT_MAX) + { + if (in_ep == 0 || out_ep == 0) + { + usage(); + } + if ((in_ep & 0x80) == 0) + { + fprintf(stderr, "IN_EP must have bit 7 set\n"); + return (EX_USAGE); + } + + if (argc > 0) + { + for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--) + { + unsigned n = strtoul(argv[out_len], 0, 0); + if (n > 255) + fprintf(stderr, + "Warning: data #%d 0x%0x > 0xff, truncating\n", + out_len, n); + out_buf[out_len] = (uint8_t)n; + } + out_len++; + if (argc > 0) + fprintf(stderr, + "Data count exceeds maximum of %d, ignoring %d elements\n", + BUFLEN, optind); + } + } + + struct libusb20_backend *be; + struct libusb20_device *dev; + + if ((be = libusb20_be_alloc_default()) == NULL) + { + perror("libusb20_be_alloc()"); + return 1; + } + + dev = NULL; + while ((dev = libusb20_be_device_foreach(be, dev)) != NULL) + { + struct LIBUSB20_DEVICE_DESC_DECODED *ddp = + libusb20_dev_get_device_desc(dev); + + printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n", + libusb20_dev_get_desc(dev), + ddp->idVendor, ddp->idProduct); + + if (ddp->idVendor == vid && ddp->idProduct == pid) + doit(dev); + } + + libusb20_be_free(be); + return 0; +} diff --git a/share/examples/libusb20/control.c b/share/examples/libusb20/control.c new file mode 100644 index 000000000000..e2ae8f74cc32 --- /dev/null +++ b/share/examples/libusb20/control.c @@ -0,0 +1,416 @@ +/*- + * SPDX-License-Identifier: Beerware + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): + * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + */ + +/* + * Simple demo program to illustrate the handling of FreeBSD's + * libusb20. + */ + +/* + * Examples: + * Just list all VID:PID pairs + * ./control + * + * Standard device request GET_STATUS, report two bytes of status + * (bit 0 in the first byte returned is the "self powered" bit) + * ./control -v 0x3eb -p 0x2103 in std dev get_status 0 0 2 + * + * Request input reports through the interrupt pipe from a mouse + * device (move the mouse around after issuing the command): + * ./control -v 0x093a -p 0x2516 -i 0x81 + * + */ + + +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> +#include <string.h> + +#include <libusb20.h> +#include <libusb20_desc.h> + +#include <sys/queue.h> + +#include "util.h" + +/* + * If you want to see the details of the internal datastructures + * in the debugger, unifdef the following. + */ +#ifdef DEBUG +# include "/usr/src/lib/libusb/libusb20_int.h" +#endif + +#define BUFLEN 64 + +#define TIMEOUT 5000 /* 5 s */ + +int intr_ep; /* endpoints */ +struct LIBUSB20_CONTROL_SETUP_DECODED setup; + +uint8_t out_buf[BUFLEN]; +uint16_t out_len; + +bool do_request; + +static void +doit(struct libusb20_device *dev) +{ + int rv; + + if (do_request) + printf("doit(): bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n", + setup.bmRequestType, + setup.bRequest, + setup.wValue, + setup.wIndex, + setup.wLength); + + /* + * Open the device, allocating memory for two possible (bulk or + * interrupt) transfers. + * + * If only control transfers are intended (via + * libusb20_dev_request_sync()), transfer_max can be given as 0. + */ + if ((rv = libusb20_dev_open(dev, 1)) != 0) + { + fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv)); + return; + } + + /* + * If the device has more than one configuration, select the desired + * one here. + */ + if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0) + { + fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv)); + return; + } + + uint8_t *data = 0; + uint16_t actlen; + + if ((setup.bmRequestType & 0x80) != 0) + { + /* this is an IN request, allocate a buffer */ + data = malloc(setup.wLength); + if (data == 0) + { + fprintf(stderr, + "Out of memory allocating %u bytes of reply buffer\n", + setup.wLength); + return; + } + } + else + data = out_buf; + + if (do_request) + { + if ((rv = libusb20_dev_request_sync(dev, &setup, data, + &actlen, + TIMEOUT, + 0 /* flags */)) != 0) + { + fprintf(stderr, + "libusb20_dev_request_sync: %s\n", libusb20_strerror(rv)); + } + printf("sent %d bytes\n", actlen); + if ((setup.bmRequestType & 0x80) != 0) + { + print_formatted(data, (uint32_t)setup.wLength); + free(data); + } + } + + if (intr_ep != 0) + { + /* + * One transfer has been requested in libusb20_dev_open() above; + * obtain the corresponding transfer struct pointer. + */ + struct libusb20_transfer *xfr_intr = libusb20_tr_get_pointer(dev, 0); + + if (xfr_intr == NULL) + { + fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv)); + return; + } + + /* + * Open the interrupt transfer. + */ + if ((rv = libusb20_tr_open(xfr_intr, 0, 1, intr_ep)) != 0) + { + fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv)); + return; + } + + uint8_t in_buf[BUFLEN]; + uint32_t rlen; + + if ((rv = libusb20_tr_bulk_intr_sync(xfr_intr, in_buf, BUFLEN, &rlen, TIMEOUT)) + != 0) + { + fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv)); + } + printf("received %d bytes\n", rlen); + if (rlen > 0) + print_formatted(in_buf, rlen); + + libusb20_tr_close(xfr_intr); + } + + libusb20_dev_close(dev); +} + +static void +usage(void) +{ + fprintf(stderr, + "Usage ./usb [-i <INTR_EP>] -v <VID> -p <PID> [dir type rcpt req wValue wIndex wLength [<outdata> ...]]\n"); + exit(EX_USAGE); +} + +static const char *reqnames[] = +{ + "get_status", + "clear_feature", + "res1", + "set_feature", + "res2", + "set_address", + "get_descriptor", + "set_descriptor", + "get_configuration", + "set_configuration", + "get_interface", + "set_interface", + "synch_frame", +}; + +static int +get_req(const char *reqname) +{ + size_t i; + size_t l = strlen(reqname); + + for (i = 0; + i < sizeof reqnames / sizeof reqnames[0]; + i++) + if (strncasecmp(reqname, reqnames[i], l) == 0) + return i; + + return strtoul(reqname, 0, 0); +} + + +static int +parse_req(int argc, char **argv) +{ + int idx; + uint8_t rt = 0; + + for (idx = 0; argc != 0 && idx <= 6; argc--, idx++) + switch (idx) + { + case 0: + /* dir[ection]: i[n] | o[ut] */ + if (*argv[idx] == 'i') + rt |= 0x80; + else if (*argv[idx] == 'o') + /* nop */; + else + { + fprintf(stderr, "request direction must be \"in\" or \"out\" (got %s)\n", + argv[idx]); + return -1; + } + break; + + case 1: + /* type: s[tandard] | c[lass] | v[endor] */ + if (*argv[idx] == 's') + /* nop */; + else if (*argv[idx] == 'c') + rt |= 0x20; + else if (*argv[idx] == 'v') + rt |= 0x40; + else + { + fprintf(stderr, + "request type must be one of \"standard\", \"class\", or \"vendor\" (got %s)\n", + argv[idx]); + return -1; + } + break; + + case 2: + /* rcpt: d[evice], i[nterface], e[ndpoint], o[ther] */ + if (*argv[idx] == 'd') + /* nop */; + else if (*argv[idx] == 'i') + rt |= 1; + else if (*argv[idx] == 'e') + rt |= 2; + else if (*argv[idx] == 'o') + rt |= 3; + else + { + fprintf(stderr, + "recipient must be one of \"device\", \"interface\", \"endpoint\", or \"other\" (got %s)\n", + argv[idx]); + return -1; + } + setup.bmRequestType = rt; + break; + + case 3: + setup.bRequest = get_req(argv[idx]); + break; + + case 4: + setup.wValue = strtoul(argv[idx], 0, 0); + break; + + case 5: + setup.wIndex = strtoul(argv[idx], 0, 0); + break; + + case 6: + setup.wLength = strtoul(argv[idx], 0, 0); + break; + } + + return argc; +} + + +int +main(int argc, char **argv) +{ + unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */ + int c; + + /* + * Initialize setup struct. This step is required, and initializes + * internal fields in the struct. + * + * All the "public" fields are named exactly the way as the USB + * standard describes them, namely: + * + * setup.bmRequestType: bitmask, bit 7 is direction + * bits 6/5 is request type + * (standard, class, vendor) + * bits 4..0 is recipient + * (device, interface, endpoint, + * other) + * setup.bRequest: the request itself (see get_req() for standard + * requests, or specific value) + * setup.wValue: a 16-bit value + * setup.wIndex: another 16-bit value + * setup.wLength: length of associated data transfer, direction + * depends on bit 7 of bmRequestType + */ + LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup); + + while ((c = getopt(argc, argv, "i:p:v:")) != -1) + switch (c) + { + case 'i': + intr_ep = strtol(optarg, NULL, 0); + break; + + case 'p': + pid = strtol(optarg, NULL, 0); + break; + + case 'v': + vid = strtol(optarg, NULL, 0); + break; + + default: + usage(); + break; + } + argc -= optind; + argv += optind; + + if (vid != UINT_MAX || pid != UINT_MAX) + { + if (intr_ep != 0 && (intr_ep & 0x80) == 0) + { + fprintf(stderr, "Interrupt endpoint must be of type IN\n"); + usage(); + } + + if (argc > 0) + { + do_request = true; + + int rv = parse_req(argc, argv); + if (rv < 0) + return EX_USAGE; + argc = rv; + + if (argc > 0) + { + for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--) + { + unsigned n = strtoul(argv[out_len], 0, 0); + if (n > 255) + fprintf(stderr, + "Warning: data #%d 0x%0x > 0xff, truncating\n", + out_len, n); + out_buf[out_len] = (uint8_t)n; + } + out_len++; + if (argc > 0) + fprintf(stderr, + "Data count exceeds maximum of %d, ignoring %d elements\n", + BUFLEN, optind); + } + } + } + + struct libusb20_backend *be; + struct libusb20_device *dev; + + if ((be = libusb20_be_alloc_default()) == NULL) + { + perror("libusb20_be_alloc()"); + return 1; + } + + dev = NULL; + while ((dev = libusb20_be_device_foreach(be, dev)) != NULL) + { + struct LIBUSB20_DEVICE_DESC_DECODED *ddp = + libusb20_dev_get_device_desc(dev); + + printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n", + libusb20_dev_get_desc(dev), + ddp->idVendor, ddp->idProduct); + + if (ddp->idVendor == vid && ddp->idProduct == pid) + doit(dev); + } + + libusb20_be_free(be); + return 0; +} diff --git a/share/examples/libusb20/util.c b/share/examples/libusb20/util.c new file mode 100644 index 000000000000..e57e439d8199 --- /dev/null +++ b/share/examples/libusb20/util.c @@ -0,0 +1,48 @@ +/* ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): + * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + */ + +/* + * Helper functions common to all examples + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +#include <libusb20.h> +#include <libusb20_desc.h> + +#include "util.h" + +/* + * Print "len" bytes from "buf" in hex, followed by an ASCII + * representation (somewhat resembling the output of hd(1)). + */ +void +print_formatted(uint8_t *buf, uint32_t len) +{ + int i, j; + + for (j = 0; j < len; j += 16) + { + printf("%02x: ", j); + + for (i = 0; i < 16 && i + j < len; i++) + printf("%02x ", buf[i + j]); + printf(" "); + for (i = 0; i < 16 && i + j < len; i++) + { + uint8_t c = buf[i + j]; + if(c >= ' ' && c <= '~') + printf("%c", (char)c); + else + putchar('.'); + } + putchar('\n'); + } +} diff --git a/share/examples/libusb20/util.h b/share/examples/libusb20/util.h new file mode 100644 index 000000000000..a54ba709b9e9 --- /dev/null +++ b/share/examples/libusb20/util.h @@ -0,0 +1,12 @@ +/* ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp): + * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch + * ---------------------------------------------------------------------------- + */ + +#include <stdint.h> +#include <libusb20.h> + +void print_formatted(uint8_t *buf, uint32_t len); diff --git a/share/examples/libvgl/Makefile b/share/examples/libvgl/Makefile new file mode 100644 index 000000000000..ebfa7eaa47ea --- /dev/null +++ b/share/examples/libvgl/Makefile @@ -0,0 +1,9 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/libvgl +PROG= demo +MAN= +DPADD= ${LIBVGL} +LDADD= -lvgl + +.include <bsd.prog.mk> diff --git a/share/examples/libvgl/Makefile.depend b/share/examples/libvgl/Makefile.depend new file mode 100644 index 000000000000..5f049ceb808c --- /dev/null +++ b/share/examples/libvgl/Makefile.depend @@ -0,0 +1,17 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + lib/libvgl \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/libvgl/demo.c b/share/examples/libvgl/demo.c new file mode 100644 index 000000000000..615a62815cea --- /dev/null +++ b/share/examples/libvgl/demo.c @@ -0,0 +1,122 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1991-1997 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/fbio.h> +#include <sys/kbio.h> +#include <sys/consio.h> +#include <vgl.h> + +int +main(int argc, char **argv) +{ + int y, xsize, ysize, i,j; + VGLBitmap *tmp; + + // set graphics mode, here 320x240 256 colors + // supported modes are (from <sys/consio.h>): + // SW_VGA_CG320: std VGA 320x200 256 colors + // SW_VGA_MODEX: Modex VGA 320x240 256 colors + // SW_VGA_VG640: std VGA 640x480 16 colors + VGLInit(SW_VGA_MODEX); + + // initialize mouse and show pointer + VGLMouseInit(VGL_MOUSESHOW); + + // VGLDisplay is a ptr to a struct Bitmap defined and initialized by + // libvgl. The Bitmap points directly to screen memory etc. + xsize=VGLDisplay->Xsize; + ysize=VGLDisplay->Ysize; + + // alloc a new bitmap + tmp = VGLBitmapCreate(MEMBUF, 256, 256, NULL); + VGLBitmapAllocateBits(tmp); + VGLClear(tmp, 0); + + // fill the screen with colored lines + for (y=0; y<ysize; y++) + VGLLine(VGLDisplay, 0, y, xsize-1, y, y/2 % 256); + + // draw some lines and circles just to show off + VGLLine(VGLDisplay, 0, 0, xsize-1, ysize-1, 63); + VGLLine(VGLDisplay, 0, ysize-1, xsize-1, 0, 63); + VGLLine(VGLDisplay, 0, 0, 0, ysize-1, 63); + VGLLine(VGLDisplay, xsize-1, 0, xsize-1, ysize-1, 63); + VGLEllipse(VGLDisplay, 256, 0, 256, 256, 63); + VGLEllipse(VGLDisplay, 0, 256, 256, 256, 0); + + // some text is also useful + VGLBitmapString(VGLDisplay, 100,100, + "This is text", 63, 0, 0, VGL_DIR_RIGHT); + sleep(2); + VGLBitmapString(VGLDisplay, 100,100, + "This is text", 63, 0, 0, VGL_DIR_UP); + sleep(2); + VGLBitmapString(VGLDisplay, 100,100, + "This is text", 63, 0, 0, VGL_DIR_LEFT); + sleep(2); + VGLBitmapString(VGLDisplay, 100,100, + "This is text", 63, 0, 0, VGL_DIR_DOWN); + sleep(2); + + // now show some simple bitblit + for (i=0; i<256; i++) + for (j=0; j<256; j++) + tmp->Bitmap[i+256*j] = i%16; + VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 0, 0, 128, 128); + for (i=0; i<256; i++) + for (j=0; j<256; j++) + tmp->Bitmap[i+256*j] = j%16; + VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 3, 128, 128, 128); + sleep(2); + VGLBitmapCopy(VGLDisplay, 237, 311, tmp, 64, 64, 128, 128); + VGLBitmapCopy(tmp, 32, 32, VGLDisplay, 400, 128, 128, 128); + sleep(2); + VGLBitmapCopy(VGLDisplay, 300, 300, VGLDisplay, 500, 128, 128, 128); + sleep(5); + i=0; + + // loop around drawing and copying + while (++i) { + VGLBitmapCopy(VGLDisplay, rand()%xsize, rand()%ysize, + VGLDisplay, rand()%xsize, rand()%ysize, + rand()%xsize, rand()%ysize); + VGLLine(VGLDisplay, rand()%xsize, rand()%ysize, + rand()%xsize, rand()%ysize, rand()%256); + VGLEllipse(VGLDisplay, rand()%xsize, rand()%ysize, + rand()%xsize/2, rand()%ysize/2, rand()%256); + rand(); + if (i > 1000) break; + } + + // restore screen to its original mode + VGLEnd(); + return 0; +} diff --git a/share/examples/mdoc/POSIX-copyright b/share/examples/mdoc/POSIX-copyright new file mode 100644 index 000000000000..144b15559307 --- /dev/null +++ b/share/examples/mdoc/POSIX-copyright @@ -0,0 +1,36 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) [year] [your name] +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" diff --git a/share/examples/mdoc/deshallify.sh b/share/examples/mdoc/deshallify.sh new file mode 100644 index 000000000000..b0493f5033d0 --- /dev/null +++ b/share/examples/mdoc/deshallify.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# Script to remove shall clauses. +# +# +sed -e 's/s shall define/s define/g' \ + -e 's/shall define/defines/g' \ + -e 's/shall attempt/attempts/g' \ + -e 's/shall include/includes/g' \ + -e 's/shall return zero and have/returns zero and has/g' \ + -e 's/shall return/returns/g' \ + -e 's/shall also include/also includes/g' \ + -e 's/pipe or FIFO shall be /pipe of FIFO are /g' \ + -e 's/s shall be /s are /g' \ + -e 's/shall be /is /g' \ + -e 's/s shall create/s create/g' \ + -e 's/shall create /creates /g' \ + -e 's/shall perform/performs/g' \ + -e 's/shall affect the/affect the/g' \ + -e 's/s shall have/s have/g' \ + -e 's/shall have/has/g' \ + -e 's/shall transfer/transfers/g' \ + -e 's/shall block/blocks/g' \ + -e 's/shall not block/does not block/g' \ + -e 's/shall occur/occurs/g' \ + -e 's/shall complete/complete/g' \ + -e 's/shall mark for update/marks for update/g' \ + -e 's/s shall fail/s fail/g' \ + -e 's/shall fail/fails/g' \ + -e 's/s shall generate/s generate/g' \ + -e 's/shall generate/generates/g' \ + -e 's/shall place/places/g' \ + -e 's/s shall default/s default/g' \ + -e 's/shall default/defaults/g' \ + -e 's/pplications shall ensure/pplications must ensure/g' \ + -e 's/pplication shall ensure/pplication must ensure/g' \ + -e 's/shall always begin/always begins/g' \ + -e 's/s shall begin /s begin /g' \ + -e 's/shall begin /begins /g' \ + -e 's/shall always contain /always contains /g' \ + -e 's/shall produce/produces/g' \ + -e 's/shall appear/appears/g' \ + -e 's/s shall be$/s are/g' \ + -e 's/shall be$/is/g' \ + -e 's/which shall result /which results /g' \ + -e 's/s shall not/s are not/g' \ + -e 's/shall not be/is not/g' \ + -e 's/shall not/is not/g' \ + -e 's/s shall behave/s behave/g' \ + -e 's/shall behave/behaves/g' \ + -e 's/shall specify/specifies/g' \ + -e 's/s shall override/s override/g' \ + -e 's/shall override/overrides/g' \ + -e 's/shall apply /applies /g' \ + -e 's/s shall start/s start/g' \ + -e 's/shall start /starts /g' \ + -e 's/s shall affect/s affect/g' \ + -e 's/shall affect/affects/g' \ + -e 's/s shall indicate/s indicate/g' \ + -e 's/shall indicate/indicates/g' \ + -e 's/shall set /set /g' \ + -e 's/s shall recognize/s recognize/g' \ + -e 's/shall recognize /recognizes /g' \ + -e 's/shall also be /is also /g' \ + -e 's/s shall enter/s enter/g' \ + -e 's/shall enter /enters /g' \ + -e 's/shall take /take /g' \ + -e 's/they shall only take /they only take /g' \ + -e 's/shall consist /consist /g' \ + -e 's/s shall cause/s cause/g' \ + -e 's/shall cause/causes/g' \ + -e 's/s shall replace/s replace/g' \ + -e 's/shall replace/replaces/g' \ + -e 's/shall become/becomes/g' \ + -e 's/shall each consist/each consist/g' \ + $1 > $1.x diff --git a/share/examples/mdoc/example.1 b/share/examples/mdoc/example.1 new file mode 100644 index 000000000000..0bdabe95aa95 --- /dev/null +++ b/share/examples/mdoc/example.1 @@ -0,0 +1,155 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) [year] [your name] +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Note: The date here should be updated whenever a non-trivial +.\" change is made to the manual page. +.Dd December 8, 1999 +.Dt EXAMPLE 1 +.Os +.Sh NAME +.Nm example +.Nd "example command manual page" +.Sh SYNOPSIS +.Nm +.Op Fl abc +.Op Fl d Ar argument +.Ar file +.Sh DESCRIPTION +This is an example manual page for the +.Nm +command. +It is intended that this example can be used as a template +when writing a new manual page. +.Pp +The options are as follows: +.Bl -tag -width "-d argument" +.It Fl a +Example optional +.Fl a +option. +.It Fl b +Example optional +.Fl b +option. +.It Fl c +Example optional +.Fl c +option. +.It Fl d Ar argument +Example optional +.Fl d +option with required argument +.Ar argument . +.It Ar file +Required argument +.Ar file . +.El +.Sh ENVIRONMENT +The +.Nm +command ignores the +.Ev EXAMPLE +environment variable. +.Sh FILES +.Bl -tag -width "/dev/null" -compact +.It Pa /dev/null +Example of a file in the +.Sx FILES +section. +.El +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +The following is an example of a typical usage +of the +.Nm +command: +.Pp +.Dl "example -abc -d xyzzy /dev/null" +.Sh DIAGNOSTICS +The command may fail for one of the following reasons: +.Bl -diag +.It "example error message" +An example of an error message. +.It "another example error message." +Self explanatory. +.El +.Sh COMPATIBILITY +The +.Nm +command has no known compatibility issues. +.Sh SEE ALSO +.Xr example 3 , +.Xr example 4 , +.Xr mdoc 7 , +.Xr example 9 +.Rs +.%A "A. B. Author" +.%T "Example RFC Title" +.%O RFC0000 +.Re +.Rs +.%A "A. B. Author" +.%B "Example Book Title" +.%O ISBN-0-000-00000-0 +.Re +.Rs +.%A "A. B. Author" +.%D "January 1997" +.%J "Example Journal Name" +.%T "Example Article Title" +.Re +.Sh STANDARDS +If the command conforms to some standard, such as +.St -p1003.2 +or +.St -isoC , +it should be noted here. +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 2.2 . +.Pp +Some other common +.Sx HISTORY +section examples are: +.Pp +The +.Nm +manual page example first appeared in +.Bx 4.4 . +.Pp +The +.Nm +manual page example first appeared in +.At v6 . +.Sh AUTHORS +This +manual page was written by +.An Mike Pritchard Aq Mt mpp@FreeBSD.org . +.Sh BUGS +The actual code for this command is vaporware. diff --git a/share/examples/mdoc/example.3 b/share/examples/mdoc/example.3 new file mode 100644 index 000000000000..c4e85062cad1 --- /dev/null +++ b/share/examples/mdoc/example.3 @@ -0,0 +1,335 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) [year] [your name] +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Note: The date here should be updated whenever a non-trivial +.\" change is made to the manual page. +.Dd July 30, 2004 +.Dt EXAMPLE 3 +.Os +.Sh NAME +.Nm example +.Nd "example library function manual page" +.Sh LIBRARY +.\" Note: list of available libraries is available in mdoc(7) +.Lb libc +.Sh SYNOPSIS +.In example.h +.Ft int +.Fn example "char *ptr" "int mode" +.Sh DESCRIPTION +This is an example library function manual page for the +.Fn example +function. +It is intended that this example can be used as a template +when writing a new manual page. +.Pp +The +.Fn example +function takes two arguments: +.Fa ptr +and +.Fa mode . +The argument +.Fa mode +may have one of the following values: +.Bl -tag -width "EXAMPLE_ONE" +.It Dv EXAMPLE_ONE +First example of a defined variable. +.Dv EXAMPLE_ONE +is described below. +.It Dv EXAMPLE_TWO +Second example. +.El +.Pp +The above values are defined in +.In example.h +as follows: +.Bd -literal +#define EXAMPLE_ONE 1 +#define EXAMPLE_TWO 2 +.Ed +.Sh IMPLEMENTATION NOTES +The +.Fn example +function is not actually implemented. +.Sh RETURN VALUES +.Rv -std example +.Sh ENVIRONMENT +The +.Fn example +library function ignores the +.Ev EXAMPLE +environment variable. +.Sh FILES +.Bl -tag -width "/dev/null" -compact +.It Pa /dev/null +Example of a file in the +.Sx FILES +section. +.El +.Sh DIAGNOSTICS +None. +.Sh COMPATIBILITY +The +.Fn example +function has no known compatibility issues. +.Sh ERRORS +.\" Delete any errno's that are not returned by your +.\" function or system call and then tailor the +.\" remaining text as needed. +The +.Fn example +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +Operation not permitted. +.It Bq Er ENOENT +No such file or directory. +.It Bq Er ESRCH +No such process. +.It Bq Er EINTR +Interrupted system call. +.It Bq Er EIO +Input/output error. +.It Bq Er ENXIO +Device not configured. +.It Bq Er E2BIG +Argument list too long. +.It Bq Er ENOEXEC +Exec format error. +.It Bq Er EBADF +Bad file descriptor. +.It Bq Er ECHILD +No child processes. +.It Bq Er EDEADLK +Resource deadlock avoided. +.It Bq Er ENOMEM +Cannot allocate memory. +.It Bq Er EACCES +Permission denied. +.It Bq Er EFAULT +Bad address. +.It Bq Er ENOTBLK +Block device required. +.It Bq Er EBUSY +Device busy. +.It Bq Er EEXIST +File exists. +.It Bq Er EXDEV +Cross-device link. +.It Bq Er ENODEV +Operation not supported by device. +.It Bq Er ENOTDIR +Not a directory. +.It Bq Er EISDIR +Is a directory. +.It Bq Er EINVAL +Invalid argument. +.It Bq Er ENFILE +Too many open files in system. +.It Bq Er EMFILE +Too many open files. +.It Bq Er ENOTTY +Inappropriate ioctl for device. +.It Bq Er ETXTBSY +Text file busy. +.It Bq Er EFBIG +File too large. +.It Bq Er ENOSPC +No space left on device. +.It Bq Er ESPIPE +Illegal seek. +.It Bq Er EROFS +Read-only file system. +.It Bq Er EMLINK +Too many links. +.It Bq Er EPIPE +Broken pipe. +.It Bq Er EDOM +Numerical argument out of domain. +.It Bq Er ERANGE +Result too large. +.It Bq Er EAGAIN +Resource temporarily unavailable. +.It Bq Er EWOULDBLOCK +Operation would block. +.It Bq Er EINPROGRESS +Operation now in progress. +.It Bq Er EALREADY +Operation already in progress. +.It Bq Er ENOTSOCK +Socket operation on non-socket. +.It Bq Er EDESTADDRREQ +Destination address required. +.It Bq Er EMSGSIZE +Message too long. +.It Bq Er EPROTOTYPE +Protocol wrong type for socket. +.It Bq Er ENOPROTOOPT +Protocol not available. +.It Bq Er EPROTONOSUPPORT +Protocol not supported. +.It Bq Er ESOCKTNOSUPPORT +Socket type not supported. +.It Bq Er EOPNOTSUPP +Operation not supported. +.It Bq Er EPFNOSUPPORT +Protocol family not supported. +.It Bq Er EAFNOSUPPORT +Address family not supported by protocol family. +.It Bq Er EADDRINUSE +Address already in use. +.It Bq Er EADDRNOTAVAIL +Cannot assign requested address. +.It Bq Er ENETDOWN +Network is down. +.It Bq Er ENETUNREACH +Network is unreachable. +.It Bq Er ENETRESET +Network dropped connection on reset. +.It Bq Er ECONNABORTED +Software causes connection abort. +.It Bq Er ENOBUFS +No buffer space available. +.It Bq Er EISCONN +Socket is already connected. +.It Bq Er ENOTCONN +Socket is not connected. +.It Bq Er ESHUTDOWN +Cannot send after socket shutdown. +.It Bq Er ETOOMANYREFS +Too many references: cannot splice. +.It Bq Er ETIMEDOUT +Operation timed out. +.It Bq Er ECONNREFUSED +Connection refused. +.It Bq Er ELOOP +Too many levels of symbolic links. +.It Bq Er ENAMETOOLONG +File name too long. +.It Bq Er EHOSTDOWN +Host is down. +.It Bq Er EHOSTUNREACH +No route to host. +.It Bq Er ENOTEMPTY +Directory not empty. +.It Bq Er EPROCLIM +Too many processes. +.It Bq Er EUSERS +Too many users. +.It Bq Er EDQUOT +Disc quota exceeded. +.It Bq Er ESTALE +Stale NFS file handle. +.It Bq Er EREMOTE +Too many levels of remote in path. +.It Bq Er EBADRPC +RPC struct is bad. +.It Bq Er ERPCMISMATCH +RPC version wrong. +.It Bq Er EPROGUNAVAIL +RPC program not available. +.It Bq Er EPROGMISMATCH +Program version wrong. +.It Bq Er EPROCUNAVAIL +Bad procedure for program. +.It Bq Er ENOLCK +No locks available. +.It Bq Er ENOSYS +Function not implemented. +.It Bq Er EFTYPE +Inappropriate file type or format. +.It Bq Er EAUTH +Authentication error. +.It Bq Er ENEEDAUTH +Need authenticator. +.It Bq Er EIDRM +Identifier removed. +.It Bq Er ENOMSG +No message of desired type. +.It Bq Er EOVERFLOW +Value too large to be stored in data type. +.It Bq Er ECANCELED +Operation canceled. +.It Bq Er EILSEQ +Illegal byte sequence. +.It Bq Er ENOATTR +Attribute not found. +.It Bq Er EDOOFUS +Programming error. +.El +.Sh SEE ALSO +.Xr example 1 , +.Xr example 4 , +.Xr mdoc 7 , +.Xr example 9 +.Rs +.%A "A. B. Author" +.%T "Example RFC Title" +.%O RFC0000 +.Re +.Rs +.%A "A. B. Author" +.%B "Example Book Title" +.%O ISBN-0-000-00000-0 +.Re +.Rs +.%A "A. B. Author" +.%D "January 1997" +.%J "Example Journal Name" +.%T "Example Article Title" +.Re +.Sh STANDARDS +If the function conforms to some standard, such as +.St -p1003.1-2004 +or +.St -isoC-99 , +it should be noted here. +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 2.2 . +.Pp +Some other common +.Sx HISTORY +section examples are: +.Pp +The +.Nm +manual page example first appeared in +.Bx 4.4 . +.Pp +The +.Nm +manual page example first appeared in +.At v6 . +.Sh AUTHORS +This +manual page was written by +.An Mike Pritchard Aq Mt mpp@FreeBSD.org . +.Sh BUGS +The actual code for this function is vaporware. diff --git a/share/examples/mdoc/example.4 b/share/examples/mdoc/example.4 new file mode 100644 index 000000000000..47ae5456b79a --- /dev/null +++ b/share/examples/mdoc/example.4 @@ -0,0 +1,123 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) [year] [your name] +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Note: The date here should be updated whenever a non-trivial +.\" change is made to the manual page. +.Dd July 31, 2015 +.Dt EXAMPLE 4 i386 +.Os +.Sh NAME +.Nm example +.Nd "example device driver manual page" +.Sh SYNOPSIS +To compile the driver into the kernel, +place the following lines in the +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device example" +.Cd "options EXAMPLE_DEBUG" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +example_load="YES" +.Ed +.Sh DESCRIPTION +This is an example device driver manual page for the +.Nm +driver. +It is intended that this example can be used as a template +when writing a new manual page. +.Pp +The +.Nm +driver supports the following ioctls: +.Bl -tag -width "EIOCNULL" +.It Dv EIOCEX +Example ioctl. +.It Dv EIOCNULL +Example ioctl. +.El +.Pp +If the kernel is compiled with the +.Dv EXAMPLE_DEBUG +option, then additional debugging messages will be displayed. +.Sh HARDWARE +The +.Nm +driver supports the following example hardware: +.Pp +.Bl -bullet -compact +.It +Example device 4201 +.It +Example device 4202 +.El +.Sh FILES +.Bl -tag -width "/dev/null" -compact +.It Pa /dev/null +Example of a file in the +.Sx FILES +section. +.El +.Sh DIAGNOSTICS +.Bl -diag +.It "example%d: example diagnostic message." +An example of a diagnostic message. +.It "example%d: another example diagnostic message." +Self explanatory. +.El +.Sh SEE ALSO +.Xr example 1 , +.Xr example 3 , +.Xr mdoc 7 , +.Xr example 9 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 2.2 . +.Pp +Some other common +.Sx HISTORY +section examples are: +.Pp +The +.Nm +manual page example first appeared in +.Bx 4.4 . +.Pp +The +.Nm +manual page example first appeared in +.At v6 . +.Sh AUTHORS +This manual page was written by +.An Mike Pritchard Aq Mt mpp@FreeBSD.org . +.Sh BUGS +The actual code for this device driver is vaporware. diff --git a/share/examples/mdoc/example.9 b/share/examples/mdoc/example.9 new file mode 100644 index 000000000000..1dd24a99fd42 --- /dev/null +++ b/share/examples/mdoc/example.9 @@ -0,0 +1,343 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) [year] [your name] +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Note: The date here should be updated whenever a non-trivial +.\" change is made to the manual page. +.Dd September 27, 2006 +.Dt EXAMPLE 9 +.Os +.Sh NAME +.Nm example +.Nd "example kernel interface manual page" +.Sh SYNOPSIS +.In sys/example.h +.Ft int +.Fn example "char *ptr" "int mode" +.Sh DESCRIPTION +This is an example manual page for the +.Fn example +kernel function. +It is intended that this example can be used as a template +when writing a new manual page. +.Pp +The +.Fn example +function takes two arguments: +.Fa ptr +and +.Fa mode . +The argument +.Fa mode +may have one of the following values: +.Bl -tag -width "EXAMPLE_ONE" +.It Dv EXAMPLE_ONE +First example of a defined variable. +.Dv EXAMPLE_ONE +is described below. +.It Dv EXAMPLE_TWO +Second example. +.El +.Pp +The above values are defined in +.In example.h +as follows: +.Bd -literal +#define EXAMPLE_ONE 1 +#define EXAMPLE_TWO 2 +.Ed +.Sh IMPLEMENTATION NOTES +The +.Fn example +function is not actually implemented. +.Sh LOCKING +The +.Va example_lock +lock must be held before +.Fn example +is called. +.Pp +Since +.Va example_lock +is a +.Xr mutex 9 , +no sleepable locks (i.e., +.Xr sx 9 +locks) can be acquired in +.Fn example . +.Sh RETURN VALUES +The +.Fn example +function returns the value 0 if successful; +otherwise one of the values listed in the +.Sx ERRORS +section is returned, to indicate the error. +.Sh EXAMPLES +.Bd -literal + int error; + + mtx_lock(&example_lock); + if ((error = example(NULL, EXAMPLE_ONE)) != 0) { + mtx_unlock(&example_lock); + return (error); + } + mtx_unlock(&example_lock); +.Ed +.Sh COMPATIBILITY +The +.Fn example +function has no known compatibility issues. +.Sh ERRORS +.\" Delete any errno's that are not returned by your +.\" function or system call and then tailor the +.\" remaining text as needed. +The +.Fn example +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +Operation not permitted. +.It Bq Er ENOENT +No such file or directory. +.It Bq Er ESRCH +No such process. +.It Bq Er EINTR +Interrupted system call. +.It Bq Er EIO +Input/output error. +.It Bq Er ENXIO +Device not configured. +.It Bq Er E2BIG +Argument list too long. +.It Bq Er ENOEXEC +Exec format error. +.It Bq Er EBADF +Bad file descriptor. +.It Bq Er ECHILD +No child processes. +.It Bq Er EDEADLK +Resource deadlock avoided. +.It Bq Er ENOMEM +Cannot allocate memory. +.It Bq Er EACCES +Permission denied. +.It Bq Er EFAULT +Bad address. +.It Bq Er ENOTBLK +Block device required. +.It Bq Er EBUSY +Device busy. +.It Bq Er EEXIST +File exists. +.It Bq Er EXDEV +Cross-device link. +.It Bq Er ENODEV +Operation not supported by device. +.It Bq Er ENOTDIR +Not a directory. +.It Bq Er EISDIR +Is a directory. +.It Bq Er EINVAL +Invalid argument. +.It Bq Er ENFILE +Too many open files in system. +.It Bq Er EMFILE +Too many open files. +.It Bq Er ENOTTY +Inappropriate ioctl for device. +.It Bq Er ETXTBSY +Text file busy. +.It Bq Er EFBIG +File too large. +.It Bq Er ENOSPC +No space left on device. +.It Bq Er ESPIPE +Illegal seek. +.It Bq Er EROFS +Read-only file system. +.It Bq Er EMLINK +Too many links. +.It Bq Er EPIPE +Broken pipe. +.It Bq Er EDOM +Numerical argument out of domain. +.It Bq Er ERANGE +Result too large. +.It Bq Er EAGAIN +Resource temporarily unavailable. +.It Bq Er EWOULDBLOCK +Operation would block. +.It Bq Er EINPROGRESS +Operation now in progress. +.It Bq Er EALREADY +Operation already in progress. +.It Bq Er ENOTSOCK +Socket operation on non-socket. +.It Bq Er EDESTADDRREQ +Destination address required. +.It Bq Er EMSGSIZE +Message too long. +.It Bq Er EPROTOTYPE +Protocol wrong type for socket. +.It Bq Er ENOPROTOOPT +Protocol not available. +.It Bq Er EPROTONOSUPPORT +Protocol not supported. +.It Bq Er ESOCKTNOSUPPORT +Socket type not supported. +.It Bq Er EOPNOTSUPP +Operation not supported. +.It Bq Er EPFNOSUPPORT +Protocol family not supported. +.It Bq Er EAFNOSUPPORT +Address family not supported by protocol family. +.It Bq Er EADDRINUSE +Address already in use. +.It Bq Er EADDRNOTAVAIL +Cannot assign requested address. +.It Bq Er ENETDOWN +Network is down. +.It Bq Er ENETUNREACH +Network is unreachable. +.It Bq Er ENETRESET +Network dropped connection on reset. +.It Bq Er ECONNABORTED +Software causes connection abort. +.It Bq Er ENOBUFS +No buffer space available. +.It Bq Er EISCONN +Socket is already connected. +.It Bq Er ENOTCONN +Socket is not connected. +.It Bq Er ESHUTDOWN +Cannot send after socket shutdown. +.It Bq Er ETOOMANYREFS +Too many references: cannot splice. +.It Bq Er ETIMEDOUT +Operation timed out. +.It Bq Er ECONNREFUSED +Connection refused. +.It Bq Er ELOOP +Too many levels of symbolic links. +.It Bq Er ENAMETOOLONG +File name too long. +.It Bq Er EHOSTDOWN +Host is down. +.It Bq Er EHOSTUNREACH +No route to host. +.It Bq Er ENOTEMPTY +Directory not empty. +.It Bq Er EPROCLIM +Too many processes. +.It Bq Er EUSERS +Too many users. +.It Bq Er EDQUOT +Disc quota exceeded. +.It Bq Er ESTALE +Stale NFS file handle. +.It Bq Er EREMOTE +Too many levels of remote in path. +.It Bq Er EBADRPC +RPC struct is bad. +.It Bq Er ERPCMISMATCH +RPC version wrong. +.It Bq Er EPROGUNAVAIL +RPC program not available. +.It Bq Er EPROGMISMATCH +Program version wrong. +.It Bq Er EPROCUNAVAIL +Bad procedure for program. +.It Bq Er ENOLCK +No locks available. +.It Bq Er ENOSYS +Function not implemented. +.It Bq Er EFTYPE +Inappropriate file type or format. +.It Bq Er EAUTH +Authentication error. +.It Bq Er ENEEDAUTH +Need authenticator. +.It Bq Er EIDRM +Identifier removed. +.It Bq Er ENOMSG +No message of desired type. +.It Bq Er EOVERFLOW +Value too large to be stored in data type. +.It Bq Er ECANCELED +Operation canceled. +.It Bq Er EILSEQ +Illegal byte sequence. +.It Bq Er ENOATTR +Attribute not found. +.It Bq Er EDOOFUS +Programming error. +.El +.Sh SEE ALSO +.Xr example 1 , +.Xr example 3 , +.Xr example 4 , +.Xr mdoc 7 , +.Xr mutex 9 +.Rs +.%A "A. B. Author" +.%T "Example RFC Title" +.%O RFC0000 +.Re +.Rs +.%A "A. B. Author" +.%B "Example Book Title" +.%O ISBN-0-000-00000-0 +.Re +.Rs +.%A "A. B. Author" +.%D "January 1997" +.%J "Example Journal Name" +.%T "Example Article Title" +.Re +.Sh HISTORY +The +.Nm +manual page example first appeared in +.Fx 6.0 . +.Pp +Some other common +.Sx HISTORY +section examples are: +.Pp +The +.Nm +manual page example first appeared in +.Bx 4.4 . +.Pp +The +.Nm +manual page example first appeared in +.At v6 . +.Sh AUTHORS +This +manual page was written by +.An Giorgos Keramidas Aq Mt keramida@FreeBSD.org . +.Sh BUGS +The actual code for this function is vaporware. diff --git a/share/examples/modules/Makefile b/share/examples/modules/Makefile new file mode 100644 index 000000000000..0f0a2fb01e8a --- /dev/null +++ b/share/examples/modules/Makefile @@ -0,0 +1,6 @@ +.PATH: ${SRCTOP}/sys/skel + +KMOD= skel +SRCS= skel.c + +.include <bsd.kmod.mk> diff --git a/share/examples/modules/skel.c b/share/examples/modules/skel.c new file mode 100644 index 000000000000..3c2cbd8eb8b1 --- /dev/null +++ b/share/examples/modules/skel.c @@ -0,0 +1,86 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 George V. Neville-Neil + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * SKEL Loadable Kernel Module for the FreeBSD Operating System + * + * The SKEL module is meant to act as a skeleton for creating new + * kernel modules. + * + * This module can be loaded and unloaded from * FreeBSD and is for + * use in teaching as well. + * + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/module.h> + +/* + * Every module can have a module specific piece of code that is + * executed whenever the module is loaded or unloaded. The following + * is a trivial example that prints a message on the console whenever + * the module is loaded or unloaded. + */ + +static int +skel_mod_event(module_t mod, int type, void *data) +{ + + switch (type) { + case MOD_LOAD: + printf("SKEL module loading.\n"); + return (0); + case MOD_UNLOAD: + printf("SKEL module unloading.\n"); + return (0); + } + return (EOPNOTSUPP); +} + +/* + * Modules can have associated data and the module data also contains + * an entry for the function called by the kernel on load and unload. + */ + +static moduledata_t skel_mod = { + "skel", + skel_mod_event, + NULL, +}; + +/* + * Each module is declared with its name and module data. The + * ordering arguments at the end put this module into the device + * driver class, which is sufficient for our needs. The complete list + * of modules types and ording can be found in sys/kernel.h + */ + +DECLARE_MODULE(skel, skel_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); + diff --git a/share/examples/netgraph/ether.bridge b/share/examples/netgraph/ether.bridge new file mode 100644 index 000000000000..6a9dd5c36c6e --- /dev/null +++ b/share/examples/netgraph/ether.bridge @@ -0,0 +1,169 @@ +#!/bin/sh +# This script sets up an Ethernet bridging network across multiple +# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph +# node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Give your bridging network a name by editing the definition of +# ${BRIDGE_NAME} below. It must be a valid netgraph node name. +# +# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES} +# as described below to define your bridging interfaces. +# +# 3. Run this script with "start" as the command line argument. +# +# 4. Examine bridging statistics by running this script with "stats" +# as the command line argument. +# +# 5. Stop bridging by running this script with "stop" as the +# command line argument. +# +# To run multiple independent bridging networks, create multiple +# copies of this script with different variable definitions. +# +# To make a "brouted" network, with IP being routed and other protocols being +# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES. +# If you just want a normal bridge, just one will be enough. +# In some cases you may want some combination. +# + +# Give each bridging network a unique name here. + +BRIDGE_NAME="bnet0" + +# List the names of the interfaces that you want to bridge across +# here in ${BRIDGE_IFACES}. If you want to include the local host +# machine as well then set ${LOCAL_IFACES} as well (they may also be +# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must +# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE} +# then assign it the empty string. + +BRIDGE_IFACES="de0 fxp0 fxp1" +LOCAL_IFACES="fxp0 fxp1" + +##################################################################### +#### Everything below this point should not need to be modified. #### +##################################################################### + +# Routine to verify node's existence. +bridge_verify() { + ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "${BRIDGE_NAME}: bridge network not found" + exit 1 + fi +} + +# Routine to get and display link stats. +bridge_linkstats() { + STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1` + if [ $? -ne 0 ]; then + exit 1 + fi + echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \ + printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }' +} + +# Start/restart routine. +bridge_start() { + + # Load netgraph KLD's as necessary. + for KLD in ng_ether ng_bridge; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces. + bridge_stop + + # Verify all interfaces exist. + for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do + if ! ngctl info ${ETHER}: >/dev/null 2>&1; then + echo "Error: interface ${ETHER} does not exist" + exit 1 + fi + ifconfig ${ETHER} up || exit 1 + done + + # Create new ng_bridge(4) node, attached to the first interface. + FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'` + ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1 + ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1 + + # Attach other interfaces as well. + LINKNUM=0 + for ETHER in ${BRIDGE_IFACES}; do + if [ ${LINKNUM} != 0 ]; then + ngctl connect ${ETHER}: ${BRIDGE_NAME}: \ + lower link${LINKNUM} || exit 1 + fi + LINKNUM=`expr ${LINKNUM} + 1` + done + + # Hook up local interface, if any. + for LOCAL_IFACE in ${LOCAL_IFACES}; do + ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \ + upper link${LINKNUM} || exit 1 + LINKNUM=`expr ${LINKNUM} + 1` + done + + # Set all interfaces in promiscuous mode and don't overwrite src addr. + for ETHER in ${BRIDGE_IFACES}; do + ngctl msg ${ETHER}: setpromisc 1 || exit 1 + ngctl msg ${ETHER}: setautosrc 0 || exit 1 + done +} + +# Stop routine. +bridge_stop() { + ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1 + for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do + ngctl kill ${ETHER}: >/dev/null 2>&1 + done +} + +# Stats routine. +bridge_stats() { + + # Make sure node exists. + bridge_verify + + echo "" + echo "Statistics for bridging network ${BRIDGE_NAME}:" + echo "" + LINKNUM=0 + for ETHER in ${BRIDGE_IFACES}; do + echo "Network interface ${ETHER}:" + bridge_linkstats ${LINKNUM} + LINKNUM=`expr ${LINKNUM} + 1` + done + for LOCAL_IFACE in ${LOCAL_IFACES}; do + echo "Local host interface ${LOCAL_IFACE}:" + bridge_linkstats ${LINKNUM} + LINKNUM=`expr ${LINKNUM} + 1` + done +} + +# Main entry point. +case $1 in + start) + bridge_start + ;; + stats) + bridge_verify + bridge_stats + ;; + stop) + bridge_verify + bridge_stop + ;; + *) + echo "usage: $0 [ start | stop | stats ]" + exit 1 +esac diff --git a/share/examples/netgraph/frame_relay b/share/examples/netgraph/frame_relay new file mode 100644 index 000000000000..0113f76076da --- /dev/null +++ b/share/examples/netgraph/frame_relay @@ -0,0 +1,45 @@ +#!/bin/sh +# script to set up a frame relay link on the sr card. +# The dlci used is selected below. The default is 16 + +CARD=sr0 +DLCI=16 + +# create a frame_relay type node and attach it to the sync port. +ngctl mkpeer ${CARD}: frame_relay rawdata downstream + +# Attach the dlci output of the (de)multiplexor to a new +# Link management protocol node. +ngctl mkpeer ${CARD}:rawdata lmi dlci0 auto0 + +# Also attach dlci 1023, as it needs both to try auto-configuring. +# The Link management protocol is now alive and probing.. +ngctl connect ${CARD}:rawdata ${CARD}:rawdata.dlci0 dlci1023 auto1023 + +# Attach the DLCI(channel) the Telco has assigned you to +# a node to handle whatever protocol encapsulation your peer +# is using. In this case RFC1490 encapsulation. +ngctl mkpeer ${CARD}:rawdata rfc1490 dlci${DLCI} downstream + + +# Attach the ip (inet) protocol output of the protocol mux to the ip (inet) +# input of a netgraph "interface" node (ifconfig should show it as "ng0"). +#if interface ng0 needs to be created use a mkpeer command.. e.g. +ngctl mkpeer ${CARD}:rawdata.dlci${DLCI} iface inet inet + +# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g. +# ngctl connect ${CARD}:rawdata.dlci${DLCI} ng0: inet inet + +# Then use ifconfig on interface ng0 as usual + +# A variant on this whole set might use the 'name' command to make it more +# readable. But it doesn't work if you have multiple lines or dlcis +# e.g. +# ngctl mkpeer ${CARD}: frame_relay rawdata downstream +# ngctl name ${CARD}:rawdata mux +# ngctl mkpeer mux: lmi dlci0 auto0 +# ngctl name mux:dlci0 lmi +# ngctl connect mux: lmi: dlci1023 auto1023 +# ngctl mkpeer mux: rfc1490 dlci${DLCI} downstream +# ngctl mux:dlci${DLCI} protomux +# ngctl mkpeer protomux: iface inet inet diff --git a/share/examples/netgraph/ngctl b/share/examples/netgraph/ngctl new file mode 100644 index 000000000000..c879cbea7b0f --- /dev/null +++ b/share/examples/netgraph/ngctl @@ -0,0 +1,172 @@ + +# +# This is an example that shows how to send ASCII formatted control +# messages to a node using ngctl(8). +# +# What we will do here create a divert(4) tap. This simply dumps +# out all packets diverted by some ipfw(8) divert rule to the console. +# +# Lines that begin with ``$'' (shell prompt) or ``+'' (ngctl prompt) +# indicate user input +# + +# First, start up ngctl in interactive mode: + + $ ngctl + Available commands: + connect Connects hook <peerhook> of the node at <relpath> to <hook> + debug Get/set debugging verbosity level + help Show command summary or get more help on a specific command + list Show information about all nodes + mkpeer Create and connect a new node to the node at "path" + msg Send a netgraph control message to the node at "path" + name Assign name <name> to the node at <path> + read Read and execute commands from a file + rmhook Disconnect hook "hook" of the node at "path" + show Show information about the node at <path> + shutdown Shutdown the node at <path> + status Get human readable status information from the node at <path> + types Show information about all installed node types + quit Exit program + + + +# Now let's create a ng_ksocket(4) node, in the family PF_DIVERT, +# of type SOCK_RAW: + + + mkpeer ksocket foo divert/raw/0 + +# Note that ``foo'' is the hook name on the socket node, which can be +# anything. The ``inet/raw/divert'' is the hook name on the ksocket +# node, which tells it what kind of socket to create. + +# Lets give our ksocket node a global name. How about ``fred'': + + + name foo fred + +# Note that we used ngctl's ``name'' command to do this. However, +# the following manually constructed netgraph message would have +# accomplished the exact same thing: + + + msg foo name { name="fred" } + +# Here we are using the ASCII <-> binary control message conversion +# routines. ngctl does this for us automatically when we use the +# ``msg'' command. + +# Now lets bind the socket associated with the ksocket node to a port +# supplied by the system. We do this by sending the ksocket node a +# ``bind'' control message. Again, ngctl does the conversion of the +# control message from ASCII to binary behind the scenes. + + + msg fred: bind inet/192.168.1.1 + +# The ksocket accepts arbitrary sockaddr structures, but also has +# special support for the PF_LOCAL and PF_INET protocol families. +# That is why we can specify the struct sockaddr argument to the +# ``bind'' command as ``inet/192.168.1.1'' (since we didn't specify +# a port number, it's assumed to be zero). We could have also +# relied on the generic sockaddr syntax and instead said this: + + + msg fred: bind { family=2 len=16 data=[ 2=192 168 1 1 ] } + +# This is what you would have to do for protocol families other +# that PF_INET and PF_LOCAL, at least until special handling for +# new ones is added. + +# The reason for the ``2=192'' is to skip the two byte IP port number, +# which causes it to be set to zero, the default value for integral +# types when parsing. Now since we didn't ask for a specific port +# number, we need to do a ``getname'' to see what port number we got: + + + msg fred: getname + Rec'd response "getname" (5) from "fred:": + Args: inet/192.168.1.1:1029 + +# As soon as we sent the message, we got back a response. Here +# ngctl is telling us that it received a control message with the +# NGF_RESP (response) flag set, the response was to a prior ``getname'' +# control message, that the originator was the node addressable +# as ``fred:''. The message arguments field is then displayed to +# us in its ASCII form. In this case, what we get back is a struct +# sockaddr, and there we see that our port number is 1029. + +# So now let's add the ipfw divert rule for whatever packets we +# want to see. How about anything from 192.168.1.129. + + + ^Z + Suspended + $ ipfw add 100 divert 1029 ip from 192.168.1.129 to any + 00100 divert 1029 ip from 192.168.1.129 to any + $ fg + +# Now watch what happens when we try to ping from that machine: + + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 57 00 00 00 20 01 bf ee c0 a8 01 81 E..<W... ....... + 0010: c0 a8 01 01 08 00 49 5c 03 00 01 00 61 62 63 64 ......I\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 58 00 00 00 20 01 be ee c0 a8 01 81 E..<X... ....... + 0010: c0 a8 01 01 08 00 48 5c 03 00 02 00 61 62 63 64 ......H\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + Rec'd data packet on hook "foo": + 0000: 45 00 00 3c 59 00 00 00 20 01 bd ee c0 a8 01 81 E..<Y... ....... + 0010: c0 a8 01 01 08 00 47 5c 03 00 03 00 61 62 63 64 ......G\....abcd + 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst + 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi + + + +# So we're seeing the output from the ksocket socket appear on the ``foo'' +# hook of ngctl's socket node. Since the packets are getting diverted, +# the 192.168.1.129 machine doesn't see any response from us. + +# Of course, any type of socket can be used, even TCP: + + + mkpeer ksocket bar inet/stream/tcp + + msg bar connect inet/192.168.1.33:13 + ngctl: send msg: Operation now in progress + + + Rec'd data packet on hook "foo": + 0000: 4d 6f 6e 20 4e 6f 76 20 32 39 20 31 37 3a 34 38 Mon Nov 29 17:48 + 0010: 3a 33 37 20 31 39 39 39 0d 0a :37 1999.. + + + +# Or, UNIX domain: + + + mkpeer ksocket bar local/stream/0 + + msg bar bind local/"/tmp/bar.socket" + + + +# Here's an example of a more complicated ASCII control message argument. +# If you look in /sys/netgraph/ng_message.h, you will see that a node +# responds to a NGM_LISTHOOKS with a struct hooklist, which contains +# an array of struct linkinfo: +# +# /* Structure used for NGM_LISTHOOKS */ +# struct linkinfo { +# char ourhook[NG_HOOKSIZ]; /* hook name */ +# char peerhook[NG_HOOKSIZ]; /* peer hook */ +# struct nodeinfo nodeinfo; +# }; +# +# struct hooklist { +# struct nodeinfo nodeinfo; /* node information */ +# struct linkinfo link[0]; /* info about each hook */ +# }; +# +# By sending a node the ``listhooks'' command using ngctl, we can see +# this structure in ASCII form (lines wrapped for readability): + + + msg bar bind local/"/tmp/bar.socket" + + msg bar listhooks + Rec'd response "listhooks" (7) from "bar": + Args: { nodeinfo={ type="ksocket" id=9 hooks=1 } + linkinfo=[ { ourhook="local/stream/0" peerhook="bar" + nodeinfo={ name="ngctl1327" type="socket" id=8 hooks=1 } } ] } + + diff --git a/share/examples/netgraph/raw b/share/examples/netgraph/raw new file mode 100644 index 000000000000..44196780fd0c --- /dev/null +++ b/share/examples/netgraph/raw @@ -0,0 +1,15 @@ +#!/bin/sh +# script to connect a raw synchronous card to a system interface. +# Assumes the file if_sr was compiled with options NETGRAPH. + +CARD=sr0 + +# create an interface "ng0" and attach it to the sync port. +# The packets had jolly well better be IP because we are not discriminating. +ngctl mkpeer ${CARD}: iface rawdata inet + +# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g. +# ngctl connect ${CARD}: ng0: rawdata inet + +# Then use ifconfig on interface ng0 as usual + diff --git a/share/examples/netgraph/udp.tunnel b/share/examples/netgraph/udp.tunnel new file mode 100644 index 000000000000..fb589ed7e15f --- /dev/null +++ b/share/examples/netgraph/udp.tunnel @@ -0,0 +1,52 @@ +#!/bin/sh + +# This script sets up a virtual point-to-point WAN link between +# two subnets, using UDP packets as the ``WAN connection.'' +# The two subnets might be non-routable addresses behind a +# firewall. +# + +# Here define the local and remote inside networks as well +# as the local and remote outside IP addresses and UDP port +# number that will be used for the tunnel. +# +LOC_INTERIOR_IP=192.168.1.1 +LOC_EXTERIOR_IP=1.1.1.1 +REM_INTERIOR_IP=192.168.2.1 +REM_EXTERIOR_IP=2.2.2.2 +REM_INSIDE_NET=192.168.2.0 +UDP_TUNNEL_PORT=4028 + +# Create the interface node ``ng0'' if it doesn't exist already, +# otherwise just make sure it's not connected to anything. +# In FreeBSD, interfaces cannot be removed so it might already +# be there from before. +# +if ifconfig ng0 >/dev/null 2>&1; then + ifconfig ng0 inet down delete >/dev/null 2>&1 + ngctl shutdown ng0: +else + ngctl mkpeer iface dummy inet +fi + +# Attach a UDP socket to the ``inet'' hook of the interface node +# using the ng_ksocket(4) node type. +# +ngctl mkpeer ng0: ksocket inet inet/dgram/udp + +# Bind the UDP socket to the local external IP address and port +# +ngctl msg ng0:inet bind inet/${LOC_EXTERIOR_IP}:${UDP_TUNNEL_PORT} + +# Connect the UDP socket to the peer's external IP address and port +# +ngctl msg ng0:inet connect inet/${REM_EXTERIOR_IP}:${UDP_TUNNEL_PORT} + +# Configure the point-to-point interface +# +ifconfig ng0 ${LOC_INTERIOR_IP} ${REM_INTERIOR_IP} + +# Add a route to the peer's interior network via the tunnel +# +route add ${REM_INSIDE_NET} ${REM_INTERIOR_IP} + diff --git a/share/examples/netgraph/virtual.chain b/share/examples/netgraph/virtual.chain new file mode 100644 index 000000000000..615f7da20a52 --- /dev/null +++ b/share/examples/netgraph/virtual.chain @@ -0,0 +1,369 @@ +#!/bin/sh +# +# Copyright (c) 2010, Yavuz Gokirmak +# +# All rights reserved. +# +# This source code may be used, modified, copied, distributed, and +# sold, in both source and binary form provided that the above +# copyright and these terms are retained, verbatim, as the first +# lines of this file. Under no circumstances is the author +# responsible for the proper functioning of the software nor does +# the author assume any responsibility for damages incurred with +# its use. +# +# +# This script creates and connects n router like nodes. Complex wide +# area topologies can be created with the help of script. +# +# Virtual nodes are generated via jails and network connections are +# established using ng_eiface(4) node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual +# nodes. Virtual topology definition includes node names and their +# IP address. Target top. syntax: ( name|ip<->name|ip ... ) +# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...) +# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...) +# +# 2. Run this script with "start" as the command line argument. +# +# 3. Add necessary static route commands for each virtual node. For +# example assume you have three virtual nodes connected each other +# like a chain (n1 is connected to n2, n2 is connected to n3). +# In order to establish connectivity among these virtual nodes, +# you have to add default routes to node n1 and node n3. Example +# static route command is: +# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" +# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" +# After defining default routes with above format you have to set +# the total number of static route commands as: +# STATIC_ROUTE_CNT=2 +# +# 4. Stop bridging by running this script with "stop" as the +# command line argument. +# +# 5. This script uses a template file in order to carry information +# between start and stop calls. +# In the start call, the netgraph interfaces and jails are created. +# At the stop phase, all created objects should be removed. +# DO NOT delete the temporary file between the start and stop phases. +# +# Target Topology: +# +# +---------------+ +---------------------------------------------+ +# | n1 (vimage) | | n2 (vimage) | +# | | | | +# | +-----------+ | | +-----------+ +-----------+ +-----------+ | +# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | | +# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| | +# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ | +# | |ether| | | |ether| |ether| |ether| | +# | +-X---+ | | +--X--+ +--X--+ +--X--+ | +# +-------X-------+ +------X--------------X---------------X-------+ +# X X X X +# X X X X +# XXXXXXXXXXXXXXX X X +# X X +# +--------X------+ +--------X------+ +# | -+--X--+- | | -+--X--+- | +# | |ether| | | |ether| | +# | +--+-----+--+ | | +--+-----+--+ | +# | | ngeth3 | | | | ngeth5 | | +# | |(ng_eiface)| | | |(ng_eiface)| | +# | +-----------+ | | +-----------+ | +# | | | | +# | n3 (vimage) | | n4 (vimage) | +# +---------------+ +---------------+ +# +# +# + +# List the names of virtual nodes and their IP addresses. Use ':' +# character to separate node name from node IP address and netmask. + +TARGET_TOPOLOGY="n1|10.0.2.1/30<->n2|10.0.2.2/30 n2|10.0.2.5/30<->n3|10.0.2.6/30 n2|10.0.2.9/30<->n4|10.0.2.10/30" +STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2" +STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5" +STATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9" +STATIC_ROUTE_CNT=3 + +# MAC manufacturer prefix. This can be modified according to needs. +MAC_PREFIX="00:1d:92" + +# Temporary file is important for proper execution of script. +TEMP_FILE="/var/tmp/.virtual.chain.tmp" + +# Set root directory for jails to be created. +JAIL_PATH="/usr/jails/router" + + +#################################################################### +#### Nothing below this point should need to be modified. #### +#################################################################### + + +# Start/restart routine. +virtual_chain_start() { + + # Load netgraph KLD's as necessary. + + for KLD in ng_ether ng_bridge ng_eiface; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces and jails. If temporary file can not be found + # script assumes that there is no previous configuration. + + if [ ! -e ${TEMP_FILE} ]; then + echo "No previous configuration(${TEMP_FILE}) found to clean-up." + else + echo -n "Cleaning previous configuration..." + virtual_chain_stop + echo "done" + fi + + # Create temporary file for usage. This file includes generated + # interface names and jail names. All bridges, interfaces and jails + # are written to file while created. In clean-up process written + # objects are cleaned (i.e. removed) from system. + + if [ -e ${TEMP_FILE} ]; then + touch ${TEMP_FILE} + fi + + + # Attach other interfaces as well. + for CONNECTION in ${TARGET_TOPOLOGY}; do + + # Virtual connections are defined in TARGET_TOPOLOGY variable. + # They have the form of 'nodeName|IPaddr'. Below two lines split + + PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'` + PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'` + PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'` + + PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'` + PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'` + PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'` + + # !!! if not created already.. + # Create virtual node (jail) with given name and using + # JAIL_PATH as root directory for jail. + + virtual_chain_create_peer_if_necessary ${PEER1_NAME} + virtual_chain_create_peer_if_necessary ${PEER2_NAME} + + # create an interface for peer with the given peer IP. Get interface + # for future use; you will connect this interface to the other + # peers' (PEER2) interface. + virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP} + PEER1_INTERFACE=${RET_INTERFACE} + + # create an interface for peer with the given peer IP. Get interface + # for future use; you will connect this interface to the other + # peers' (PEER2) interface. + virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP} + PEER2_INTERFACE=${RET_INTERFACE} + + # Connect virtual interface to other interface. Syntax is : + # ngctl connect INTERFACE1: INTERFACE2: ether ether. + + echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..." + ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \ + || exit 1 + echo "done" + + done + + # Executes static route add commands. + i=0 + while [ $i != $STATIC_ROUTE_CNT ]; do + eval ROUTE=\${STATIC_ROUTE${i}} + ret=`${ROUTE}` + i=`expr $i + 1` + done + + echo "Virtual WAN established successfully!" +} + +virtual_chain_create_interface_with_ip() { + + NODE_NAME=$1 + NODE_IP=$2 + + # Create a ng_eiface object for virtual node. ng_eiface + # object has a hook that can be connected to one of bridge + # links. After creating interface get its automatically + # generated name for further usage. + + echo "Creating eiface interface for virtual node ${NODE_NAME}." + ngctl mkpeer eiface ether ether + EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` + echo "Interface ${EIFACE} is created." + + # Write name of the interface to temp file. Clean-up procedure + # will use this name to shutdown interface. + + echo "interface ${EIFACE}" >> ${TEMP_FILE} + + # Move virtual interface to virtual node. Note that Interface + # name will not be changed at the end of this movement. Moved + # interface can be seen at the output of ifconfig command in + # jail: 'jexec jailname ifconfig' + + echo "Moving ${EIFACE} to ${NODE_NAME}" + ifconfig ${EIFACE} vnet ${NODE_NAME} + + # Make lo0 interface localhost. + jexec ${NODE_NAME} ifconfig lo0 localhost + + # Generate a random mac address for virtual interface. First + # three octets can be changed by user. Last three octets are + # generated randomly. + M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + + MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` + + # Set the link address (mac address) of virtual interface in + # virtual node to randomly generated MAC. + echo "Setting MAC address of ${EIFACE} to '${MAC}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC + + # Either IPv4 or IPv6 can be used in this script. Ifconfig + # IP setting syntax differs slightly for two IP versions. + # For version 4 'inet' keyword is used whereas for version 6 + # 'inet6' is used. Below line tries to decide which IP version + # is given and sets IPVER to 'inet' or 'inet6'. + + IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ + if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ + last[1]<256) print "inet"; else print "inet6"}'` + + # Set IP address of virtual interface in virtual node. + echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} + + RET_INTERFACE=${EIFACE} +} + +virtual_chain_create_peer_if_necessary() { + + if ! grep -q $1 ${TEMP_FILE} ; then + + echo -n "Creating virtual node (jail) ${1}..." + jail -c vnet name=${1} host.hostname=${1} \ + path=${JAIL_PATH} persist + jexec ${1} sysctl -w net.inet.ip.forwarding=1 + jexec ${1} sysctl -w net.inet6.ip6.forwarding=1 + echo "done" + + # Write name of the jail to temp file. Clean-up + # procedure will use this name to remove jail. + + echo "node ${1}" >> ${TEMP_FILE} + fi + +} + +# Stop routine. +virtual_chain_stop() { + + if [ ! -e ${TEMP_FILE} ]; then + echo "Nothing to stop! ${TEMP_FILE}: temp file not found" + else + + echo -n "Shutdown bridge interface.." + OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` + for BRIDGE in ${OBJECTS}; do + ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Shutdown all eiface interfaces..." + OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` + for INTERFACE in ${OBJECTS}; do + ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Removing all jails..." + OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` + for NODE in ${OBJECTS}; do + jail -r ${NODE} + done + echo "done" + + echo "Removing tempfile ${TEMP_FILE}" + rm ${TEMP_FILE} + fi + echo "Virtual LAN objects removed successfully!" + +} + +virtual_chain_usage() { + echo "usage: $0 start [target_topology]" + echo " : $0 [ stop | help ]" +} + + +# Main entry point. + +case $# in + 1) + case $1 in + start) + echo -n "Creating default target topology:" + echo " ${TARGET_TOPOLOGY}" + virtual_chain_start + ;; + stop) + + if [ ! -e ${TEMP_FILE} ]; then + echo -n "Noting to stop! ${TEMP_FILE}:" + echo " temp file not found" + else + virtual_chain_stop + fi + ;; + help) + virtual_chain_usage + exit 1 + ;; + *) + virtual_chain_usage + exit 1 + + esac + ;; + 2) + case $1 in + start) + TARGET_TOPOLOGY=$2 + echo -n "Creating target topology:" + echo "${TARGET_TOPOLOGY}" + virtual_chain_start + ;; + *) + virtual_chain_usage + exit 1 + esac + ;; + + *) + virtual_chain_usage + exit 1 +esac + diff --git a/share/examples/netgraph/virtual.lan b/share/examples/netgraph/virtual.lan new file mode 100644 index 000000000000..2ec47aa08b51 --- /dev/null +++ b/share/examples/netgraph/virtual.lan @@ -0,0 +1,358 @@ +#!/bin/sh +# +# Copyright (c) 2010, Yavuz Gokirmak +# +# All rights reserved. +# +# This source code may be used, modified, copied, distributed, and +# sold, in both source and binary form provided that the above +# copyright and these terms are retained, verbatim, as the first +# lines of this file. Under no circumstances is the author +# responsible for the proper functioning of the software nor does +# the author assume any responsibility for damages incurred with +# its use. +# +# +# This script adds virtual nodes to one of the physical interfaces +# visible on your local area network (LAN). Virtual nodes seems real +# to external observers. +# If traceroute is executed to one of virtual nodes, the IP +# address of the physical interface will not be seen in the output. +# Virtual nodes are generated via jails and network connections are +# established using ng_bridge(4) and ng_eiface(4) node types. +# +# To use this script: +# +# 0. Make your own copy of this example script. +# +# 1. Edit the definition of ${ETHER_INTF} as described below +# to define your real interface connected to the LAN. Virtual nodes +# will placed on the same physical network as this interface. +# +# 2. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual +# nodes. Virtual topology definition includes node names and their +# IP address. Target top. syntax: ( node1|ip1/24 node2|ip2/24 ... ) +# Example 1: ( n1|122.122.122.12/24, n2|122.122.122.13/24 ...) +# Example 2: ( n1|2001:b90::14a/125, n1|2001:b90::14b/125 ...) +# +# 3. Run this script with "start" as the command line argument. +# +# 4. Stop bridging by running this script with "stop" as the +# command line argument. +# +# 5. This script uses a template file in order to carry information +# between start and stop calls. +# In the start call, the netgraph interfaces and jails are created. +# At the stop phase, all created objects should be removed. +# DO NOT delete the temporary file between the start and stop phases. +# +# To add virtual nodes for multiple independent LANs, create multiple +# copies of this script with different variable definitions. +# +# Target Topology: +# +# +# +---------------+ +---------------+ +---------------+ +# | n0 (vimage) | | n1 (vimage) | | nk (vimage) | +# | | | | | | +# | +-----------+ | | +-----------+ | | +-----------+ | +# | | ngeth0 | | | | ngeth1 | | | | ngethk | | +# | |(ng_eiface)| | | |(ng_eiface)| | | |(ng_eiface)| | +# | +--+-----+--+ | | +--+-----+--+ | | +--+-----+--+ | +# | |ether| | | |ether| | | |ether| | +# | +--X--+ | | +--X--+ | | +---X-+ | +# +-----+ +--------\------+ +--------\------+ +-------/-------+ +# |upper|----\ \ip_addr \ip_addr /ip_addr +# +-+-----+--+ \ \ \ \ +# | em0 | \ +--------+ +-+ \ +# |(ng_ether)| +-----------+ \ \ \ +# +-+-----+--+ \ \ / \ +# |lower| +---------\ \ \ / / +# +--X--+ / O--X--O O-X---O O---X-O O--X--O O---X---O +# \ | |link0| |link1| |link2| |link3| |linkk+2| +# \ / +-O-----O-O-----O-O-----O-O-----O-----O-------O-+ +# +---+ | | +# | bridge (ng_bridge) | +# +-----------------------------------------------+ +# +# + +# Give the name of ethernet interface. Virtual nodes will be seen as +# local neighbours of this interface. + +ETHER_INTF="em0" + +# List the names of virtual nodes and their IP addresses. Use ':' +# character to separate node name from node IP address and netmask. + +TARGET_TOPOLOGY="c1|10.0.2.20/24 c2|10.0.2.21/24 c3|10.0.2.22/24" + +# MAC manufacturer prefix. This can be modified according to needs. +MAC_PREFIX="00:1d:92" + +# Temporary file is important for proper execution of script. +TEMP_FILE="/var/tmp/.virtual.lan.tmp" + +# Set root directory for jails to be created. +JAIL_PATH="/usr/jails/node" + + +#################################################################### +#### Nothing below this point should need to be modified. #### +#################################################################### + + +# Start/restart routine. +virtual_lan_start() { + + # Load netgraph KLD's as necessary. + + for KLD in ng_ether ng_bridge ng_eiface; do + if ! kldstat -v | grep -qw ${KLD}; then + echo -n "Loading ${KLD}.ko... " + kldload ${KLD} || exit 1 + echo "done" + fi + done + + # Reset all interfaces and jails. If temporary file can not be found + # script assumes that there is no previous configuration. + + if [ ! -e ${TEMP_FILE} ]; then + echo "No previous configuration(${TEMP_FILE}) found to clean-up." + else + echo -n "Cleaning previous configuration..." + virtual_lan_stop + echo "done" + fi + + # Create temporary file for usage. This file includes generated + # interface names and jail names. All bridges, interfaces and jails + # are written to file while created. In clean-up process written + # objects are cleaned (i.e. removed) from system. + + if [ -e ${TEMP_FILE} ]; then + touch ${TEMP_FILE} + fi + + echo -n "Verifying ethernet interface existence..." + # Verify ethernet interface exist. + if ! ngctl info ${ETHER_INTF}: >/dev/null 2>&1; then + echo "Error: interface ${ETHER_INTF} does not exist" + exit 1 + fi + ifconfig ${ETHER_INTF} up || exit 1 + echo "done" + + # Get current number of bridge interfaces in the system. This number + # is used to create a name for new bridge. + BRIDGE_COUNT=`ngctl l | grep bridge | wc -l | sed -e "s/ //g"` + BRIDGE_NAME="bridge${BRIDGE_COUNT}" + + # Create new ng_bridge(4) node and attach it to the ethernet interface. + # Connect ng_ether:lower hook to bridge:link0 when creating bridge and + # connect ng_ether:upper hook to bridge:link1 after bridge name is set. + + echo "Creating bridge interface: ${BRIDGE_NAME}..." + ngctl mkpeer ${ETHER_INTF}: bridge lower link0 || exit 1 + ngctl name ${ETHER_INTF}:lower ${BRIDGE_NAME} || exit 1 + ngctl connect ${ETHER_INTF}: ${BRIDGE_NAME}: upper link1 || exit 1 + echo "Bridge ${BRIDGE_NAME} is created and ${ETHER_INTF} is connected." + + # In the above code block two hooks are connected to bridge interface, + # therefore LINKNUM is set to 2 indicating total number of connected + # hooks on the bridge interface. + LINKNUM=2 + + # Write name of the bridge to temp file. Clean-up procedure will use + # this name to shutdown bridge interface. + echo "bridge ${BRIDGE_NAME}" > ${TEMP_FILE} + + + # Attach other interfaces as well. + for NODE in ${TARGET_TOPOLOGY}; do + + # Virtual nodes are defined in TARGET_TOPOLOGY variable. They + # have the form of 'nodeName|IPaddr'. Below two lines split + # node definition to get node name and node IP. + + NODE_NAME=`echo ${NODE} | awk -F"|" '{print $1}'` + NODE_IP=`echo ${NODE} | awk -F"|" '{print $2}'` + + # Create virtual node (jail) with given name and using + # JAIL_PATH as root directory for jail. + + echo -n "Creating virtual node (jail) ${NODE_NAME}..." + jail -c vnet name=${NODE_NAME} host.hostname=${NODE_NAME} \ + path=${JAIL_PATH} persist + echo "done" + + # Write name of the jail to temp file. Clean-up procedure will + # use this name to remove jail. + + echo "node ${NODE_NAME}" >> ${TEMP_FILE} + + # Create a ng_eiface object for virtual node. ng_eiface + # object has a hook that can be connected to one of bridge + # links. After creating interface get its automatically + # generated name for further usage. + + echo "Creating eiface interface for virtual node ${NODE_NAME}." + ngctl mkpeer eiface ether ether + EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'` + echo "Interface ${EIFACE} is created." + + # Write name of the interface to temp file. Clean-up procedure + # will use this name to shutdown interface. + + echo "interface ${EIFACE}" >> ${TEMP_FILE} + + # Move virtual interface to virtual node. Note that Interface + # name will not be changed at the end of this movement. Moved + # interface can be seen at the output of ifconfig command in + # jail: 'jexec jailname ifconfig' + + echo "Moving ${EIFACE} to ${NODE_NAME}" + ifconfig ${EIFACE} vnet ${NODE_NAME} + + # Make lo0 interface localhost. + jexec ${NODE_NAME} ifconfig lo0 localhost + + # Generate a random mac address for virtual interface. First + # three octets can be changed by user. Last three octets are + # generated randomly. + M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \ + awk '{ print $1 % 256 }'` + + MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}` + + # Set the link address (mac address) of virtual interface in + # virtual node to randomly generated MAC. + echo "Setting MAC address of ${EIFACE} to '${MAC}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC + + # Either IPv4 or IPv6 can be used in this script. Ifconfig + # IP setting syntax differs slightly for two IP versions. + # For version 4 'inet' keyword is used whereas for version 6 + # 'inet6' is used. Below line tries to decide which IP version + # is given and sets IPVER to 'inet' or 'inet6'. + + IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \ + if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \ + last[1]<256) print "inet"; else print "inet6"}'` + + # Set IP address of virtual interface in virtual node. + echo "Setting IP address of ${EIFACE} to '${NODE_IP}'" + jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP} + + # Connect virtual interface to bridge interface. Syntax is : + # ngctl connect INTERFACE: BRIDGE: INTERFACE_HOOK EMPTY_LINK. + # Interface has one hook named 'ether' and below line connects + # ether hook to bridge's first unconnected link. + + echo -n "Connecting ${EIFACE}:ether to ${BRIDGE_NAME}:link${LINKNUM}..." + ngctl connect ${EIFACE}: ${BRIDGE_NAME}: ether link${LINKNUM} \ + || exit 1 + echo "done" + + # Now, bridge has one more connected link thus link count is + # incremented. + LINKNUM=`expr ${LINKNUM} + 1` + done + echo "Virtual LAN established successfully!" + +} + +# Stop routine. +virtual_lan_stop() { + + if [ ! -e ${TEMP_FILE} ]; then + echo "Nothing to stop! ${TEMP_FILE}: temp file not found" + else + + echo -n "Shutdown bridge interface.." + OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'` + for BRIDGE in ${OBJECTS}; do + ngctl shutdown ${BRIDGE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Shutdown all eiface interfaces..." + OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'` + for INTERFACE in ${OBJECTS}; do + ngctl shutdown ${INTERFACE}: >/dev/null 2>&1 + done + echo "done" + + echo -n "Removing all jails..." + OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'` + for NODE in ${OBJECTS}; do + jail -r ${NODE} + done + echo "done" + + echo "Removing tempfile ${TEMP_FILE}" + rm ${TEMP_FILE} + fi + echo "Virtual LAN objects removed successfully!" + +} + +virtual_lan_usage() { + echo "usage: $0 start [target_topology]" + echo " : $0 [ stop | help ]" +} + + +# Main entry point. + +case $# in + 1) + case $1 in + start) + echo -n "Creating default target topology:" + echo " ${TARGET_TOPOLOGY}" + virtual_lan_start + ;; + stop) + + if [ ! -e ${TEMP_FILE} ]; then + echo -n "Noting to stop! ${TEMP_FILE}:" + echo " temp file not found" + else + virtual_lan_stop + fi + ;; + help) + virtual_lan_usage + exit 1 + ;; + *) + virtual_lan_usage + exit 1 + + esac + ;; + 2) + case $1 in + start) + TARGET_TOPOLOGY=$2 + echo -n "Creating target topology:" + echo "${TARGET_TOPOLOGY}" + virtual_lan_start + ;; + *) + virtual_lan_usage + exit 1 + esac + ;; + + *) + virtual_lan_usage + exit 1 +esac + diff --git a/share/examples/perfmon/Makefile b/share/examples/perfmon/Makefile new file mode 100644 index 000000000000..a687980e7808 --- /dev/null +++ b/share/examples/perfmon/Makefile @@ -0,0 +1,9 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/${PROG} +PROG= perfmon +MAN= + +install: + +.include <bsd.prog.mk> diff --git a/share/examples/perfmon/README b/share/examples/perfmon/README new file mode 100644 index 000000000000..25452813f3db --- /dev/null +++ b/share/examples/perfmon/README @@ -0,0 +1,23 @@ +`perfmon' is a sample program to access the performance-monitoring +counters on Pentium and Pentium Pro CPUs. See perfmon(4) for a +description of this facility. + +The program takes the following options: + + -u count events in user mode + -o count events in kernel mode + (these two can be combined) + + -e count events, not duration + -l n run `n' loops (default 50) + -s n sleep `n' seconds between loop iterations (default 0) + +The following options are not implemented on Pentium CPUs: + + -m n use count mask `n' + -i invert sense of count mask comparison + -U n use unit mask `n' + +There is one mandatory argument, which is the event number to be +monitored, defined in <machine/perfmon.h>. All numbers can be +specified in any format acceptable to strtol(3). diff --git a/share/examples/perfmon/perfmon.c b/share/examples/perfmon/perfmon.c new file mode 100644 index 000000000000..1b7afad9d69e --- /dev/null +++ b/share/examples/perfmon/perfmon.c @@ -0,0 +1,191 @@ +/* + * Copyright 1996 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/ioctl.h> + +#include <machine/cpu.h> +#include <machine/perfmon.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <unistd.h> +#include <fcntl.h> +#include <limits.h> +#include <errno.h> + +static int getnum(const char *, int, int); +static void usage(const char *) __dead2; + +int +main(int argc, char **argv) +{ + int c, fd, num; + int loops, i, sleeptime; + char *cmd; + struct pmc pmc; + struct pmc_tstamp then, now; + struct pmc_data value; + quad_t *buf; + double total; + + pmc.pmc_num = 0; + pmc.pmc_event = 0; + pmc.pmc_unit = 0; + pmc.pmc_flags = 0; + pmc.pmc_mask = 0; + cmd = NULL; + loops = 50; + sleeptime = 0; + + while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) { + switch(c) { + case 'u': + pmc.pmc_flags |= PMCF_USR; + break; + case 'o': + pmc.pmc_flags |= PMCF_OS; + break; + case 'e': + pmc.pmc_flags |= PMCF_E; + break; + case 'i': + pmc.pmc_flags |= PMCF_INV; + break; + case 'U': + pmc.pmc_unit = getnum(optarg, 0, 256); + break; + case 'm': + pmc.pmc_mask = getnum(optarg, 0, 256); + break; + case 'l': + loops = getnum(optarg, 1, INT_MAX - 1); + break; + case 's': + sleeptime = getnum(optarg, 0, INT_MAX - 1); + break; + case 'c': + cmd = optarg; + break; + default: + usage(argv[0]); + } + } + + if (argc - optind != 1) + usage(argv[0]); + + pmc.pmc_event = getnum(argv[optind], 0, 255); + + buf = malloc((loops + 1) * sizeof *buf); + if (!buf) + err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf); + + fd = open(_PATH_PERFMON, O_RDWR, 0); + if (fd < 0) + err(1, "open: " _PATH_PERFMON); + + if (ioctl(fd, PMIOSETUP, &pmc) < 0) + err(1, "ioctl(PMIOSETUP)"); + + if (ioctl(fd, PMIOTSTAMP, &then) < 0) + err(1, "ioctl(PMIOTSTAMP)"); + + num = 0; + if (ioctl(fd, PMIOSTART, &num) < 0) + err(1, "ioctl(PMIOSTART)"); + + value.pmcd_num = 0; + for (i = 0; i < loops; i++) { + if (ioctl(fd, PMIOSTOP, &num) < 0) + err(1, "ioctl(PMIOSTOP)"); + if (ioctl(fd, PMIOREAD, &value) < 0) + err(1, "ioctl(PMIOREAD)"); + buf[i] = value.pmcd_value; + if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0) + err(1, "ioctl(PMIORESET)"); + if (ioctl(fd, PMIOSTART, &num) < 0) + err(1, "ioctl(PMIOSTART)"); + if (sleeptime) + sleep(sleeptime); + if (cmd) + system(cmd); + } + + if (ioctl(fd, PMIOSTOP, &num) < 0) + err(1, "ioctl(PMIOSTOP)"); + if (ioctl(fd, PMIOREAD, &value) < 0) + err(1, "ioctl(PMIOREAD)"); + buf[i] = value.pmcd_value; + if (ioctl(fd, PMIOTSTAMP, &now) < 0) + err(1, "ioctl(PMIOTSTAMP)"); + + total = 0; + for (i = 1; i <= loops; i++) { + printf("%d: %qd\n", i, buf[i]); + total += buf[i]; + } + printf("total: %f\nmean: %f\n", total, total / loops); + + printf("clocks (at %d-MHz): %qd\n", now.pmct_rate, + now.pmct_value - then.pmct_value); + + return 0; +} + +static int +getnum(const char *buf, int min, int max) +{ + char *ep; + long l; + + errno = 0; + l = strtol(buf, &ep, 0); + if (*buf && !*ep && !errno) { + if (l < min || l > max) { + errx(1, "%s: must be between %d and %d", + buf, min, max); + } + return (int)l; + } + + errx(1, "%s: parameter must be an integer", buf); +} + +static void +usage(const char *pname) +{ + fprintf(stderr, + "usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n" + " [-U unit] counter\n", + pname); + exit(1); +} diff --git a/share/examples/pf/Makefile b/share/examples/pf/Makefile new file mode 100644 index 000000000000..4ea4f9c79bb8 --- /dev/null +++ b/share/examples/pf/Makefile @@ -0,0 +1,10 @@ + +PACKAGE=examples +FILES= faq-example1 faq-example2 faq-example3 \ + ackpri queue1 queue2 queue3 queue4 \ + pf.conf \ + spamd + +FILESDIR= ${SHAREDIR}/examples/pf + +.include <bsd.prog.mk> diff --git a/share/examples/pf/Makefile.depend b/share/examples/pf/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/pf/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/pf/ackpri b/share/examples/pf/ackpri new file mode 100644 index 000000000000..2dd42b9bb3b1 --- /dev/null +++ b/share/examples/pf/ackpri @@ -0,0 +1,30 @@ +# $OpenBSD: ackpri,v 1.3 2006/10/07 04:48:01 mcbride Exp $ + +# Use a simple priority queue to prioritize empty (no payload) TCP ACKs, +# which dramatically improves throughput on (asymmetric) links when the +# reverse direction is saturated. The empty ACKs use an insignificant +# part of the bandwidth, but if they get delayed, downloads suffer +# badly, so prioritize them. + +# Example: 512/128 kbps ADSL. Download is 50 kB/s. When a concurrent +# upload saturates the uplink, download drops to 7 kB/s. With the +# priority queue below, download drops only to 48 kB/s. + +# Replace lo0 with your real external interface + +ext_if="lo0" + +# For a 512/128 kbps ADSL with PPPoE link, using "bandwidth 100Kb" +# is optimal. Some experimentation might be needed to find the best +# value. If it's set too high, the priority queue is not effective, and +# if it's set too low, the available bandwidth is not fully used. +# A good starting point would be real_uplink_bandwidth * 90 / 100. + +altq on $ext_if priq bandwidth 100Kb queue { q_pri, q_def } +queue q_pri priority 7 +queue q_def priority 1 priq(default) + +pass out on $ext_if proto tcp from $ext_if to any queue (q_def, q_pri) + +pass in on $ext_if proto tcp from any to $ext_if queue (q_def, q_pri) + diff --git a/share/examples/pf/faq-example1 b/share/examples/pf/faq-example1 new file mode 100644 index 000000000000..9045cd86bc59 --- /dev/null +++ b/share/examples/pf/faq-example1 @@ -0,0 +1,50 @@ +# $OpenBSD: faq-example1,v 1.5 2006/10/07 04:48:01 mcbride Exp $ + +# +# Firewall for Home or Small Office +# http://www.openbsd.org/faq/pf/example1.html +# + + +# macros +ext_if="fxp0" +int_if="xl0" + +tcp_services="{ 22, 113 }" +icmp_types="echoreq" + +comp3="192.168.0.3" + +# options +set block-policy return +set loginterface $ext_if + +set skip on lo + +# scrub +scrub in + +# nat/rdr +nat on $ext_if inet from !($ext_if) -> ($ext_if:0) +nat-anchor "ftp-proxy/*" +rdr-anchor "ftp-proxy/*" + +rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021 +rdr on $ext_if proto tcp from any to any port 80 -> $comp3 + +# filter rules +block in + +pass out + +anchor "ftp-proxy/*" +antispoof quick for { lo $int_if } + +pass in on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services + +pass in on $ext_if inet proto tcp from any to $comp3 port 80 \ + synproxy state + +pass in inet proto icmp all icmp-type $icmp_types + +pass quick on $int_if no state diff --git a/share/examples/pf/faq-example2 b/share/examples/pf/faq-example2 new file mode 100644 index 000000000000..e3dea440e83a --- /dev/null +++ b/share/examples/pf/faq-example2 @@ -0,0 +1,88 @@ +# $OpenBSD: faq-example2,v 1.4 2006/10/07 04:48:01 mcbride Exp $ + +# +# Small, Home Network +# http://www.openbsd.org/faq/pf/queueing.html#example1 +# + + +# enable queueing on the external interface to control traffic going to +# the Internet. use the priq scheduler to control only priorities. set +# the bandwidth to 610Kbps to get the best performance out of the TCP +# ACK queue. + +altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \ + tcp_ack_out } + +# define the parameters for the child queues. +# std_out - the standard queue. any filter rule below that does not +# explicitly specify a queue will have its traffic added +# to this queue. +# ssh_im_out - interactive SSH and various instant message traffic. +# dns_out - DNS queries. +# tcp_ack_out - TCP ACK packets with no data payload. + +queue std_out priq(default) +queue ssh_im_out priority 4 priq(red) +queue dns_out priority 5 +queue tcp_ack_out priority 6 + +# enable queueing on the internal interface to control traffic coming in +# from the Internet. use the cbq scheduler to control bandwidth. max +# bandwidth is 2Mbps. + +altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in } + +# define the parameters for the child queues. +# std_in - the standard queue. any filter rule below that does not +# explicitly specify a queue will have its traffic added +# to this queue. +# ssh_im_in - interactive SSH and various instant message traffic. +# dns_in - DNS replies. +# bob_in - bandwidth reserved for Bob's workstation. allow him to +# borrow. + +queue std_in bandwidth 1.6Mb cbq(default) +queue ssh_im_in bandwidth 200Kb priority 4 +queue dns_in bandwidth 120Kb priority 5 +queue bob_in bandwidth 80Kb cbq(borrow) + + +# ... in the filtering section of pf.conf ... + +alice = "192.168.0.2" +bob = "192.168.0.3" +charlie = "192.168.0.4" +local_net = "192.168.0.0/24" +ssh_ports = "{ 22 2022 }" +im_ports = "{ 1863 5190 5222 }" + +# filter rules for fxp0 inbound +block in on fxp0 all + +# filter rules for fxp0 outbound +block out on fxp0 all +pass out on fxp0 inet proto tcp from (fxp0) to any \ + queue(std_out, tcp_ack_out) +pass out on fxp0 inet proto { udp icmp } from (fxp0) to any +pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \ + queue dns_out +pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \ + queue(std_out, ssh_im_out) +pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \ + queue(ssh_im_out, tcp_ack_out) + +# filter rules for dc0 inbound +block in on dc0 all +pass in on dc0 from $local_net + +# filter rules for dc0 outbound +block out on dc0 all +pass out on dc0 from any to $local_net +pass out on dc0 proto { tcp udp } from any port domain to $local_net \ + queue dns_in +pass out on dc0 proto tcp from any port $ssh_ports to $local_net \ + queue(std_in, ssh_im_in) +pass out on dc0 proto tcp from any port $im_ports to $local_net \ + queue ssh_im_in +pass out on dc0 from any to $bob queue bob_in diff --git a/share/examples/pf/faq-example3 b/share/examples/pf/faq-example3 new file mode 100644 index 000000000000..b4793110842d --- /dev/null +++ b/share/examples/pf/faq-example3 @@ -0,0 +1,116 @@ +# $OpenBSD: faq-example3,v 1.4 2006/10/07 04:48:01 mcbride Exp $ + +# +# Company Network +# http://www.openbsd.org/faq/pf/queueing.html#example2 +# + + +# enable queueing on the external interface to queue packets going out +# to the Internet. use the cbq scheduler so that the bandwidth use of +# each queue can be controlled. the max outgoing bandwidth is 1.5Mbps. + +altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext } + +# define the parameters for the child queues. +# std_ext - the standard queue. also the default queue for +# outgoing traffic on fxp0. +# www_ext - container queue for WWW server queues. limit to +# 500Kbps. +# www_ext_http - http traffic from the WWW server; higher priority. +# www_ext_misc - all non-http traffic from the WWW server. +# boss_ext - traffic coming from the boss's computer. + +queue std_ext bandwidth 500Kb cbq(default borrow) +queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc } + queue www_ext_http bandwidth 50% priority 3 cbq(red borrow) + queue www_ext_misc bandwidth 50% priority 1 cbq(borrow) +queue boss_ext bandwidth 500Kb priority 3 cbq(borrow) + +# enable queueing on the internal interface to control traffic coming +# from the Internet or the DMZ. use the cbq scheduler to control the +# bandwidth of each queue. bandwidth on this interface is set to the +# maximum. traffic coming from the DMZ will be able to use all of this +# bandwidth while traffic coming from the Internet will be limited to +# 1.0Mbps (because 0.5Mbps (500Kbps) is being allocated to fxp1). + +altq on dc0 cbq bandwidth 100% queue { net_int, www_int } + +# define the parameters for the child queues. +# net_int - container queue for traffic from the Internet. bandwidth +# is 1.0Mbps. +# std_int - the standard queue. also the default queue for outgoing +# traffic on dc0. +# it_int - traffic to the IT Dept network; reserve them 500Kbps. +# boss_int - traffic to the boss's PC; assign a higher priority. +# www_int - traffic from the WWW server in the DMZ; full speed. + +queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int } + queue std_int bandwidth 250Kb cbq(default borrow) + queue it_int bandwidth 500Kb cbq(borrow) + queue boss_int bandwidth 250Kb priority 3 cbq(borrow) +queue www_int bandwidth 99Mb cbq(red borrow) + +# enable queueing on the DMZ interface to control traffic destined for +# the WWW server. cbq will be used on this interface since detailed +# control of bandwidth is necessary. bandwidth on this interface is set +# to the maximum. traffic from the internal network will be able to use +# all of this bandwidth while traffic from the Internet will be limited +# to 500Kbps. + +altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz } + +# define the parameters for the child queues. +# internal_dmz - traffic from the internal network. +# net_dmz - container queue for traffic from the Internet. +# net_dmz_http - http traffic; higher priority. +# net_dmz_misc - all non-http traffic. this is also the default queue. + +queue internal_dmz bandwidth 99Mb cbq(borrow) +queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc } + queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow) + queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow) + + +# ... in the filtering section of pf.conf ... + +main_net = "192.168.0.0/24" +it_net = "192.168.1.0/24" +int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }" +dmz_net = "10.0.0.0/24" + +boss = "192.168.0.200" +wwwserv = "10.0.0.100" + +# default deny +block on { fxp0, fxp1, dc0 } all + +# filter rules for fxp0 inbound +pass in on fxp0 proto tcp from any to $wwwserv port { 21, \ + > 49151 } queue www_ext_misc +pass in on fxp0 proto tcp from any to $wwwserv port 80 \ + queue www_ext_http + +# filter rules for fxp0 outbound +pass out on fxp0 from $int_nets to any +pass out on fxp0 from $boss to any queue boss_ext + +# filter rules for dc0 inbound +pass in on dc0 from $int_nets to any +pass in on dc0 from $it_net to any queue it_int +pass in on dc0 from $boss to any queue boss_int +pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \ + > 49151 } queue www_int + +# filter rules for dc0 outbound +pass out on dc0 from dc0 to $int_nets + +# filter rules for fxp1 inbound +pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53 + +# filter rules for fxp1 outbound +pass out on fxp1 proto tcp from any to $wwwserv port { 21, \ + > 49151 } queue net_dmz_misc +pass out on fxp1 proto tcp from any to $wwwserv port 80 queue net_dmz_http +pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \ + 21, > 49151 } queue internal_dmz diff --git a/share/examples/pf/pf.conf b/share/examples/pf/pf.conf new file mode 100644 index 000000000000..24b92fd9411c --- /dev/null +++ b/share/examples/pf/pf.conf @@ -0,0 +1,34 @@ +# $OpenBSD: pf.conf,v 1.34 2007/02/24 19:30:59 millert Exp $ +# +# See pf.conf(5) and /usr/share/examples/pf for syntax and examples. +# Remember to set gateway_enable="YES" and/or ipv6_gateway_enable="YES" +# in /etc/rc.conf if packets are to be forwarded between interfaces. + +#ext_if="ext0" +#int_if="int0" + +#table <spamd-white> persist + +#set skip on lo + +#scrub in + +#nat-anchor "ftp-proxy/*" +#rdr-anchor "ftp-proxy/*" +#nat on $ext_if inet from !($ext_if) -> ($ext_if:0) +#rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021 +#no rdr on $ext_if proto tcp from <spamd-white> to any port smtp +#rdr pass on $ext_if proto tcp from any to any port smtp \ +# -> 127.0.0.1 port spamd + +#anchor "ftp-proxy/*" +#block in +#pass out + +#pass quick on $int_if no state +#antispoof quick for { lo $int_if } + +#pass in on $ext_if proto tcp to ($ext_if) port ssh +#pass in log on $ext_if proto tcp to ($ext_if) port smtp +#pass out log on $ext_if proto tcp from ($ext_if) to port smtp +#pass in on $ext_if inet proto icmp from any to ($ext_if) icmp-type { unreach, redir, timex } diff --git a/share/examples/pf/queue1 b/share/examples/pf/queue1 new file mode 100644 index 000000000000..38824f38ee33 --- /dev/null +++ b/share/examples/pf/queue1 @@ -0,0 +1,20 @@ +# $OpenBSD: queue1,v 1.4 2006/10/07 04:48:01 mcbride Exp $ + +ext_if = "dc0" + +altq on $ext_if cbq bandwidth 10Mb \ + queue { deflt, http, ssh, mail, rsets } +queue deflt bandwidth 10% priority 0 cbq(default ecn) +queue http bandwidth 1.5Mb priority 3 { http_vhosts, http_cust1 } +queue http_vhosts bandwidth 40% cbq(borrow red) +queue http_cust1 bandwidth 0.5Mb +queue mail bandwidth 10% priority 1 +queue ssh bandwidth 100Kb priority 7 cbq(borrow) +queue rsets bandwidth 7500b priority 0 cbq(red) + +block return in on $ext_if inet all queue rsets +pass in on $ext_if inet proto tcp from any to any port 80 queue http +pass out on $ext_if inet proto tcp from any to any port 22 queue ssh +pass in on $ext_if inet proto tcp from any to any port 22 queue ssh +pass out on $ext_if inet proto tcp from any to any port 25 queue mail +pass out on $ext_if inet all diff --git a/share/examples/pf/queue2 b/share/examples/pf/queue2 new file mode 100644 index 000000000000..1968d8f3e8a3 --- /dev/null +++ b/share/examples/pf/queue2 @@ -0,0 +1,28 @@ +# $OpenBSD: queue2,v 1.4 2006/10/07 04:48:01 mcbride Exp $ +# advanced queue example. +# give interactive ssh traffic priority over ssh bulk transfers (scp, sftp) + +ext_if="dc0" +developerhosts="192.168.2.0/24" +employeehosts="192.168.0.0/23" + +altq on $ext_if cbq bandwidth 5Mb queue { std, http, mail, ssh } + +queue std bandwidth 10% cbq(default) +queue http bandwidth 60% priority 2 cbq(borrow red) { employees, developers } +queue developers bandwidth 75% cbq(borrow) +queue employees bandwidth 15% +queue mail bandwidth 10% priority 0 cbq(borrow ecn) +queue ssh bandwidth 20% cbq(borrow) { ssh_interactive, ssh_bulk } +queue ssh_interactive bandwidth 25% priority 7 +queue ssh_bulk bandwidth 75% priority 0 + +block return out on $ext_if inet all queue std +pass out on $ext_if inet proto tcp from $developerhosts to any port 80 \ + queue developers +pass out on $ext_if inet proto tcp from $employeehosts to any port 80 \ + queue employees +pass out on $ext_if inet proto tcp from any to any port 22 \ + queue(ssh_bulk, ssh_interactive) +pass out on $ext_if inet proto tcp from any to any port 25 \ + queue mail diff --git a/share/examples/pf/queue3 b/share/examples/pf/queue3 new file mode 100644 index 000000000000..b33e7b8f2047 --- /dev/null +++ b/share/examples/pf/queue3 @@ -0,0 +1,15 @@ +# $OpenBSD: queue3,v 1.3 2006/10/07 04:48:01 mcbride Exp $ +# simple PRIQ example + +ext_if="lo0" + +altq on $ext_if priq bandwidth 10Mb queue { pri-low pri-med pri-high } +queue pri-low priority 0 +queue pri-med priority 1 priq(default) +queue pri-high priority 2 + +pass out on $ext_if proto tcp from any to any port 22 \ + queue(pri-med, pri-high) +pass out on $ext_if proto tcp from any to any port 80 queue pri-med +pass in on $ext_if proto tcp from any to any port 80 queue pri-low + diff --git a/share/examples/pf/queue4 b/share/examples/pf/queue4 new file mode 100644 index 000000000000..e42299cff37e --- /dev/null +++ b/share/examples/pf/queue4 @@ -0,0 +1,19 @@ +# $OpenBSD: queue4,v 1.2 2003/08/22 21:50:34 david Exp $ +# +# Hierarchical queueing for a university. +# Three faculties; engineering, law and art are defined. +# Departments under the engineering faculty are defined as child queues. +# The total bandwidth for engineering faculty is shared between three +# departments. CS department gets the half of the bandwidth, EE and IE +# departments get the thirty percent and twenty percent of bandwidth +# respectively. These sibling departments can use more than their linkshare +# whenever there is no backlogged sibling queue but when a queue gets +# backlogged, it is guaranteed that the queue gets its linkshare. + +altq on dc0 bandwidth 16Mb hfsc queue { eng law art } +queue eng bandwidth 10Mb { cs ee ie } +queue cs hfsc( default linkshare 50% ) +queue ee hfsc( linkshare 30% ) +queue ie hfsc( linkshare 20% ) +queue law bandwidth 3Mb +queue art bandwidth 3Mb diff --git a/share/examples/pf/spamd b/share/examples/pf/spamd new file mode 100644 index 000000000000..31b24adc3f55 --- /dev/null +++ b/share/examples/pf/spamd @@ -0,0 +1,7 @@ +# $OpenBSD: spamd,v 1.2 2005/08/06 19:52:37 jmc Exp $ + +# spamd-setup puts addresses to be redirected into table <spamd>. + +table <spamd> persist +no rdr on { lo0, lo1 } from any to any +rdr inet proto tcp from <spamd> to any port smtp -> 127.0.0.1 port spamd diff --git a/share/examples/ppi/Makefile b/share/examples/ppi/Makefile new file mode 100644 index 000000000000..4a4d944ca50e --- /dev/null +++ b/share/examples/ppi/Makefile @@ -0,0 +1,9 @@ +# Makefile to build LCD control software for ppi(4) interface. +# + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ppi +PROG= ppilcd +MAN= + +.include <bsd.prog.mk> diff --git a/share/examples/ppi/ppilcd.c b/share/examples/ppi/ppilcd.c new file mode 100644 index 000000000000..2b3d1c4ea522 --- /dev/null +++ b/share/examples/ppi/ppilcd.c @@ -0,0 +1,436 @@ +/* + * Control LCD module hung off parallel port using the + * ppi 'geek port' interface. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <unistd.h> +#include <err.h> +#include <sysexits.h> + +#include <dev/ppbus/ppbconf.h> +#include <dev/ppbus/ppi.h> + +#define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args); + +static void usage(void); +static char *progname; + +#define DEFAULT_DEVICE "/dev/ppi0" + +/* Driver functions */ +static void hd44780_prepare(char *devname, char *options); +static void hd44780_finish(void); +static void hd44780_command(int cmd); +static void hd44780_putc(int c); + +/* + * Commands + * Note that unrecognised command escapes are passed through with + * the command value set to the ASCII value of the escaped character. + */ +#define CMD_RESET 0 +#define CMD_BKSP 1 +#define CMD_CLR 2 +#define CMD_NL 3 +#define CMD_CR 4 +#define CMD_HOME 5 + +#define MAX_DRVOPT 10 /* maximum driver-specific options */ + +struct lcd_driver +{ + char *l_code; + char *l_name; + char *l_options[MAX_DRVOPT]; + void (* l_prepare)(char *name, char *options); + void (* l_finish)(void); + void (* l_command)(int cmd); + void (* l_putc)(int c); +}; + +static struct lcd_driver lcd_drivertab[] = { + { + "hd44780", + "Hitachi HD44780 and compatibles", + { + "Reset options:", + " 1 1-line display (default 2)", + " B Cursor blink enable", + " C Cursor enable", + " F Large font select", + NULL + }, + hd44780_prepare, + hd44780_finish, + hd44780_command, + hd44780_putc + }, + { + NULL, + NULL, + { + NULL + }, + NULL, + NULL + } +}; + +static void do_char(struct lcd_driver *driver, char ch); + +int debuglevel = 0; +int vflag = 0; + +int +main(int argc, char *argv[]) +{ + extern char *optarg; + extern int optind; + struct lcd_driver *driver = &lcd_drivertab[0]; + char *drivertype, *cp; + char *devname = DEFAULT_DEVICE; + char *drvopts = NULL; + int ch, i; + + if ((progname = strrchr(argv[0], '/'))) { + progname++; + } else { + progname = argv[0]; + } + + drivertype = getenv("LCD_TYPE"); + + while ((ch = getopt(argc, argv, "Dd:f:o:v")) != -1) { + switch(ch) { + case 'D': + debuglevel++; + break; + case 'd': + drivertype = optarg; + break; + case 'f': + devname = optarg; + break; + case 'o': + drvopts = optarg; + break; + case 'v': + vflag = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + /* If an LCD type was specified, look it up */ + if (drivertype != NULL) { + driver = NULL; + for (i = 0; lcd_drivertab[i].l_code != NULL; i++) { + if (!strcmp(drivertype, lcd_drivertab[i].l_code)) { + driver = &lcd_drivertab[i]; + break; + } + } + if (driver == NULL) { + warnx("LCD driver '%s' not known", drivertype); + usage(); + } + } + debug(1, "Driver selected for %s", driver->l_name); + driver->l_prepare(devname, drvopts); + atexit(driver->l_finish); + + if (argc > 0) { + debug(2, "reading input from %d argument%s", argc, (argc > 1) ? "s" : ""); + for (i = 0; i < argc; i++) + for (cp = argv[i]; *cp; cp++) + do_char(driver, *cp); + } else { + debug(2, "reading input from stdin"); + setvbuf(stdin, NULL, _IONBF, 0); + while ((ch = fgetc(stdin)) != EOF) + do_char(driver, (char)ch); + } + exit(EX_OK); +} + +static void +usage(void) +{ + int i, j; + + fprintf(stderr, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname); + fprintf(stderr, " -D Increase debugging\n"); + fprintf(stderr, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE); + fprintf(stderr, " -d Specify driver, one of:\n"); + for (i = 0; lcd_drivertab[i].l_code != NULL; i++) { + fprintf(stderr, " %-10s (%s)%s\n", + lcd_drivertab[i].l_code, lcd_drivertab[i].l_name, (i == 0) ? " *default*" : ""); + if (lcd_drivertab[i].l_options[0] != NULL) { + + for (j = 0; lcd_drivertab[i].l_options[j] != NULL; j++) + fprintf(stderr, " %s\n", lcd_drivertab[i].l_options[j]); + } + } + fprintf(stderr, " -o Specify driver option string\n"); + fprintf(stderr, " args Message strings. Embedded escapes supported:\n"); + fprintf(stderr, " \\b Backspace\n"); + fprintf(stderr, " \\f Clear display, home cursor\n"); + fprintf(stderr, " \\n Newline\n"); + fprintf(stderr, " \\r Carriage return\n"); + fprintf(stderr, " \\R Reset display\n"); + fprintf(stderr, " \\v Home cursor\n"); + fprintf(stderr, " \\\\ Literal \\\n"); + fprintf(stderr, " If args not supplied, strings are read from standard input\n"); + exit(EX_USAGE); +} + +static void +do_char(struct lcd_driver *driver, char ch) +{ + static int esc = 0; + + if (esc) { + switch(ch) { + case 'b': + driver->l_command(CMD_BKSP); + break; + case 'f': + driver->l_command(CMD_CLR); + break; + case 'n': + driver->l_command(CMD_NL); + break; + case 'r': + driver->l_command(CMD_CR); + break; + case 'R': + driver->l_command(CMD_RESET); + break; + case 'v': + driver->l_command(CMD_HOME); + break; + case '\\': + driver->l_putc('\\'); + break; + default: + driver->l_command(ch); + break; + } + esc = 0; + } else { + if (ch == '\\') { + esc = 1; + } else { + if (vflag || isprint(ch)) + driver->l_putc(ch); + } + } +} + + +/****************************************************************************** + * Driver for the Hitachi HD44780. This is probably *the* most common driver + * to be found on one- and two-line alphanumeric LCDs. + * + * This driver assumes the following connections : + * + * Parallel Port LCD Module + * -------------------------------- + * Strobe (1) Enable (6) + * Data (2-9) Data (7-14) + * Select In (17) RS (4) + * Auto Feed (14) R/W (5) + * + * In addition, power must be supplied to the module, normally with + * a circuit similar to this: + * + * VCC (+5V) O------o-------o--------O Module pin 2 + * | | + + * / --- + * \ --- 1uF + * / | - + * \ <-----o--------O Module pin 3 + * / + * \ + * | + * GND O------o----------------O Module pin 1 + * + * The ground line should also be connected to the parallel port, on + * one of the ground pins (eg. pin 25). + * + * Note that the pinning on some LCD modules has the odd and even pins + * arranged as though reversed; check carefully before connecting a module + * as it is possible to toast the HD44780 if the power is reversed. + */ + +static int hd_fd; +static u_int8_t hd_cbits; +static int hd_lines = 2; +static int hd_blink = 0; +static int hd_cursor = 0; +static int hd_font = 0; + +#define HD_COMMAND SELECTIN +#define HD_DATA 0 +#define HD_READ 0 +#define HD_WRITE AUTOFEED + +#define HD_BF 0x80 /* internal busy flag */ +#define HD_ADDRMASK 0x7f /* DDRAM address mask */ + +#define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);} +#define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);} +#define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v) + +static void +hd44780_output(int type, int data) +{ + debug(3, "%s -> 0x%02x", (type == HD_COMMAND) ? "cmd " : "data", data); + hd_sctrl(type | HD_WRITE | STROBE); /* set direction, address */ + hd_sctrl(type | HD_WRITE); /* raise E */ + hd_sdata((u_int8_t) data); /* drive data */ + hd_sctrl(type | HD_WRITE | STROBE); /* lower E */ +} + +static int +hd44780_input(int type) +{ + u_int8_t val; + + hd_sctrl(type | HD_READ | STROBE); /* set direction, address */ + hd_sctrl(type | HD_READ); /* raise E */ + hd_gdata(val); /* read data */ + hd_sctrl(type | HD_READ | STROBE); /* lower E */ + + debug(3, "0x%02x -> %s", val, (type == HD_COMMAND) ? "cmd " : "data"); + return(val); +} + +static void +hd44780_prepare(char *devname, char *options) +{ + char *cp = options; + + if ((hd_fd = open(devname, O_RDWR, 0)) == -1) + err(EX_OSFILE, "can't open '%s'", devname); + + /* parse options */ + while (cp && *cp) { + switch (*cp++) { + case '1': + hd_lines = 1; + break; + case 'B': + hd_blink = 1; + break; + case 'C': + hd_cursor = 1; + break; + case 'F': + hd_font = 1; + break; + default: + errx(EX_USAGE, "hd44780: unknown option code '%c'", *(cp-1)); + } + } + + /* Put LCD in idle state */ + if (ioctl(hd_fd, PPIGCTRL, &hd_cbits)) /* save other control bits */ + err(EX_IOERR, "ioctl PPIGCTRL failed (not a ppi device?)"); + hd_cbits &= ~(STROBE | SELECTIN | AUTOFEED); /* set strobe, RS, R/W low */ + debug(2, "static control bits 0x%x", hd_cbits); + hd_sctrl(STROBE); + hd_sdata(0); + +} + +static void +hd44780_finish(void) +{ + close(hd_fd); +} + +static void +hd44780_command(int cmd) +{ + u_int8_t val; + + switch (cmd) { + case CMD_RESET: /* full manual reset and reconfigure as per datasheet */ + debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor", + hd_lines, hd_font ? "5x10" : "5x7", hd_cursor ? "" : " no", hd_blink ? " blinking" : ""); + val = 0x30; + if (hd_lines == 2) + val |= 0x08; + if (hd_font) + val |= 0x04; + hd44780_output(HD_COMMAND, val); + usleep(10000); + hd44780_output(HD_COMMAND, val); + usleep(1000); + hd44780_output(HD_COMMAND, val); + usleep(1000); + val = 0x08; /* display off */ + hd44780_output(HD_COMMAND, val); + usleep(1000); + val |= 0x04; /* display on */ + if (hd_cursor) + val |= 0x02; + if (hd_blink) + val |= 0x01; + hd44780_output(HD_COMMAND, val); + usleep(1000); + hd44780_output(HD_COMMAND, 0x06); /* shift cursor by increment */ + usleep(1000); + /* FALLTHROUGH */ + + case CMD_CLR: + hd44780_output(HD_COMMAND, 0x01); + usleep(2000); + break; + + case CMD_BKSP: + hd44780_output(HD_DATA, 0x10); /* shift cursor left one */ + break; + + case CMD_NL: + if (hd_lines == 2) + hd44780_output(HD_COMMAND, 0xc0); /* beginning of second line */ + break; + + case CMD_CR: + /* XXX will not work in 4-line mode, or where readback fails */ + val = hd44780_input(HD_COMMAND) & 0x3f; /* mask character position, save line pos */ + hd44780_output(HD_COMMAND, 0x80 | val); + break; + + case CMD_HOME: + hd44780_output(HD_COMMAND, 0x02); + usleep(2000); + break; + + default: + if (isprint(cmd)) { + warnx("unknown command %c", cmd); + } else { + warnx("unknown command 0x%x", cmd); + } + } + usleep(40); +} + +static void +hd44780_putc(int c) +{ + hd44780_output(HD_DATA, c); + usleep(40); +} + diff --git a/share/examples/ppp/chap-auth b/share/examples/ppp/chap-auth new file mode 100755 index 000000000000..91778949fea3 --- /dev/null +++ b/share/examples/ppp/chap-auth @@ -0,0 +1,96 @@ +#! /usr/local/bin/wish8.0 -f +# +# Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# Display a window to request a users CHAP secret, accepting the relevant +# values from ppp (``set authkey !thisprogram'') and passing the entered +# ``authname'' and ``authkey'' back to ppp. +# + +set pwidth 12; # Prompt field width +set vwidth 20; # Value field width +set fxpad 7; # Value field width +set fypad 3; # Value field width + +wm title . "PPP Authentication"; + +# We expect three lines of input from ppp +set hostname [gets stdin]; +set challenge [gets stdin]; +set authname [gets stdin]; + +proc mkhalfframe { n prompt } { + global pwidth; + + frame .$n; + text .$n.prompt -width $pwidth -height 1 -relief flat; + .$n.prompt insert 1.0 $prompt; + pack .$n.prompt -side left; + .$n.prompt configure -state disabled; +} + +proc mkframe { n prompt value entry } { + global vwidth fxpad fypad; + + mkhalfframe $n $prompt; + text .$n.value -width $vwidth -height 1; + .$n.value insert 1.0 $value; + pack .$n.value -side right; + if ($entry) { + # Allow entry, but don't encourage it + .$n.value configure -state normal -takefocus 0; + bind .$n.value <Return> {done}; + } else { + .$n.value configure -state disabled; + } + pack .$n -side top -padx $fxpad -pady $fypad; +} + +# Dump our fields to stdout and exit +proc done {} { + puts [.n.value get 1.0 {end - 1 char}]; + puts [.k.value get]; + exit 0; +} + +mkframe h "Hostname:" $hostname 0; +mkframe c "Challenge:" $challenge 0; +mkframe n "Authname:" $authname 1; + +mkhalfframe k "Authkey:"; +entry .k.value -show "*" -width $vwidth; +pack .k.value -side right; +bind .k.value <Return> {done}; +focus .k.value; +pack .k -side top -padx $fxpad -pady $fypad; + +frame .b; +button .b.ok -default active -text "Ok" -command {done}; +pack .b.ok -side left; +button .b.cancel -default normal -text "Cancel" -command {exit 1}; +pack .b.cancel -side right; +pack .b -side top -padx $fxpad -pady $fypad; diff --git a/share/examples/ppp/login-auth b/share/examples/ppp/login-auth new file mode 100755 index 000000000000..e3d34f89ddff --- /dev/null +++ b/share/examples/ppp/login-auth @@ -0,0 +1,73 @@ +#! /usr/local/bin/wish8.0 -f +# +# Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# +# Display a window to request a users password, expecting a login name +# as an argument and outputting the password to stdout. +# + +set pwidth 11; # Prompt field width +set vwidth 20; # Value field width +set fxpad 7; # Value field width +set fypad 3; # Value field width + +wm title . "PPP Login"; + +# Dump our password to stdout and exit +proc done {} { + puts [.p.value get]; + exit 0; +} + +frame .l; +text .l.prompt -width $pwidth -height 1 -relief flat; + .l.prompt insert 1.0 "Login:"; +pack .l.prompt -side left; + .l.prompt configure -state disabled; +text .l.value -width $vwidth -height 1; + .l.value insert 1.0 $argv; +pack .l.value -side right; + .l.value configure -state disabled; +pack .l -side top -padx $fxpad -pady $fypad; + +frame .p; +text .p.prompt -width $pwidth -height 1 -relief flat; + .p.prompt insert 1.0 "Password:"; +pack .p.prompt -side left; + .p.prompt configure -state disabled; +entry .p.value -show "*" -width $vwidth; +pack .p.value -side right; +bind .p.value <Return> {done}; +focus .p.value; +pack .p -side top -padx $fxpad -pady $fypad; + +frame .b; +button .b.ok -default active -text "Ok" -takefocus 0 -command {done}; +pack .b.ok -side left; +button .b.cancel -default normal -text "Cancel" -takefocus 0 -command {exit 1}; +pack .b.cancel -side right; +pack .b -side top -padx $fxpad -pady $fypad; diff --git a/share/examples/ppp/ppp.conf.sample b/share/examples/ppp/ppp.conf.sample new file mode 100644 index 000000000000..67df28d23f4f --- /dev/null +++ b/share/examples/ppp/ppp.conf.sample @@ -0,0 +1,788 @@ +################################################################# +# +# PPP Sample Configuration File +# +# Originally written by Toshiharu OHNO +# +# +################################################################# + +# This file is separated into sections. Each section is named with +# a label starting in column 0 and followed directly by a ``:''. The +# section continues until the next label. Blank lines and characters +# after a ``#'' are ignored (a literal ``#'' must be escaped with a ``\'' +# or quoted with ""). All commands inside sections that do not begin +# with ``!'' (e.g., ``!include'') *must* be indented by at least one +# space or tab or they will not be recognized! +# +# Lines beginning with "!include" will ``include'' another file. You +# may want to ``!include ~/.ppp.conf'' for backwards compatibility. +# + +# Default setup. Always executed when PPP is invoked. +# This section is *not* pre-loaded by the ``load'' or ``dial'' commands. +# +# This is the best place to specify your modem device, its DTR rate, +# your dial script and any logging specification. Logging specs should +# be done first so that the results of subsequent commands are logged. +# +default: + set log Phase Chat LCP IPCP CCP tun command + set device /dev/cuau1 + set speed 115200 + set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" AT \ + OK-AT-OK ATE1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT" + +# Client side PPP +# +# Although the PPP protocol is a peer to peer protocol, we normally +# consider the side that initiates the connection as the client and +# the side that receives the connection as the server. Authentication +# is required by the server either using a unix-style login procedure +# or by demanding PAP or CHAP authentication from the client. +# + +# An on demand example where we have dynamic IP addresses and wish to +# use a unix-style login script: +# +# If the peer assigns us an arbitrary IP (most ISPs do this) and we +# can't predict what their IP will be either, take a wild guess at +# some IPs that you can't currently route to. Ppp can change this +# when the link comes up. +# +# The /0 bit in "set ifaddr" says that we insist on 0 bits of the +# specified IP actually being correct, therefore, the other side can assign +# any IP number. +# +# The fourth arg to "set ifaddr" makes us send "0.0.0.0" as our requested +# IP number, forcing the peer to make the decision. This is necessary +# when negotiating with some (broken) ppp implementations. +# +# This entry also works with static IP numbers or when not in -auto mode. +# The ``add'' line adds a `sticky' default route that will be updated if +# and when any of the IP numbers are changed in IPCP negotiations. +# The "set ifaddr" is required in -auto mode only. +# It's better to put the ``add'' line in ppp.linkup when not in -auto mode. +# +# Finally, the ``enable dns'' line tells ppp to ask the peer for the +# nameserver addresses that should be used. This isn't always supported +# by the other side, but if it is, ppp will update /etc/resolv.conf with +# the correct nameserver values at connection time. +# +# The login script shown says that you're expecting ``ogin:''. If you +# don't receive that, send a ``\n'' and expect ``ogin:'' again. When +# it's received, send ``ppp'', expect ``word:'' then send ``ppp''. +# You *MUST* customise this login script according to your local +# requirements. +# +pmdemand: + set phone 1234567 + set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp" + set timeout 120 + set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0 + add default HISADDR + enable dns + +# If you want to use PAP or CHAP instead of using a unix-style login +# procedure, do the following. Note, the peer suggests whether we +# should send PAP or CHAP. By default, we send whatever we're asked for. +# +# You *MUST* customise ``MyName'' and ``MyKey'' below. +# +PAPorCHAPpmdemand: + set phone 1234567 + set login + set authname "MyName" + set authkey "MyKey" + set timeout 120 + set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0 + add default HISADDR + enable dns + +# On demand dialup example with static IP addresses: +# Here, the local side uses 192.244.185.226 and the remote side +# uses 192.244.176.44. +# +# # ppp -auto ondemand +# +# With static IP numbers, our setup is similar to dynamic: +# Remember, ppp.linkup is searched for a "192.244.176.44" label, then +# an "ondemand" label, and finally the "MYADDR" label. +# +ondemand: + set phone 1234567 + set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp" + set timeout 120 + set ifaddr 192.244.185.226 192.244.176.44 + add default HISADDR + enable dns + +# An on-demand dialup example using an external Terminal Adapter (TA) +# that supports multi-link ppp itself. +# +# This may be specific to the AETHRA TA. +# +TA: + set phone 12345678 # Replace this with your ISPs phone number + + set authname "somename" # Replace these with your login name & password. + set authkey "somepasswd" # This profile assumes you're using PAP or CHAP. + + enable lqr echo + set reconnect 3 5 + set redial 3 10 + set lqrperiod 45 + disable pred1 deflate mppe + deny pred1 deflate mppe + + set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" ATB41CL2048 \ + OK-AT-OK ATB40&J3E1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT" + set login + set logout + set hangup + + set timeout 60 300 # The minimum charge period is 5 minutes, so don't + # hangup before then + + set device /dev/cuau0 # Or whatever + set speed 115200 # Use as high a speed as possible + + enable dns # Ask the peer what to put in resolv.conf + + # Take a wild guess at an IP number and let the other side decide + set ifaddr 172.16.0.1/0 212.0.0.0/0 0 0 + add! default hisaddr + + set mru 1504 # Some extra room for the MP header + + set server /var/run/ppp/ppp-TA "" 0177 # The diagnostic port (-rw-------) + + +# Example segments +# +# The following lines may be included as part of your configuration +# section and aren't themselves complete. They're provided as examples +# of how to achieve different things. + +examples: +# Multi-phone example. Numbers separated by a : are used sequentially. +# Numbers separated by a | are used if the previous dial or login script +# failed. Usually, you will prefer to use only one of | or :, but both +# are allowed. +# + set phone 12345678|12345679:12345670|12345671 +# +# Some phone numbers may include # characters - don't forget to escape +# (or quote) them: +# + set phone "12345##678" +# +# Ppp can accept control instructions from the ``pppctl'' program. +# First, you must set up your control socket. It's safest to use +# a UNIX domain socket, and watch the permissions: +# + set server /var/run/ppp/internet MySecretPassword 0177 +# +# Although a TCP port may be used if you want to allow control +# connections from other machines: +# + set server 6670 MySecretpassword +# +# If you don't like ppp's builtin chat, use an external one: +# + set login "\"!chat \\-f /etc/ppp/ppp.dev.chat\"" +# +# If we have a ``strange'' modem that must be re-initialized when we +# hangup: +# + set hangup "\"\" AT OK-AT-OK ATZ OK" +# +# To adjust logging without blowing away the setting in default: +# + set log -command +tcp/ip +# +# To see log messages on the screen in interactive mode: +# + set log local LCP IPCP CCP +# +# If you're seeing a lot of magic number problems and failed connections, +# try this (see the man page): +# + set openmode active 5 +# +# For noisy lines, we may want to reconnect (up to 20 times) after loss +# of carrier, with 3 second delays between each attempt: +# + set reconnect 3 20 +# +# When playing server for M$ clients, tell them who our NetBIOS name +# servers are: +# + set nbns 10.0.0.1 10.0.0.2 +# +# Inform the client if they ask for our DNS IP numbers: +# + enable dns +# +# If you don't want to tell them what's in your /etc/resolv.conf file +# with `enable dns', override the values: +# + set dns 10.0.0.1 10.0.0.2 +# +# Some people like to prioritize DNS packets: +# + set urgent udp +53 +# +# If we're using the -nat switch, redirect ftp and http to an internal +# machine: +# + nat port tcp 10.0.0.2:ftp ftp + nat port tcp 10.0.0.2:http http +# +# or don't trust the outside at all +# + nat deny_incoming yes +# +# I trust user brian to run ppp, so this goes in the `default' section: +# + allow user brian +# +# But label `internet' contains passwords that even brian can't have, so +# I empty out the user access list in that section so that only root can +# have access: +# + allow users +# +# I also may wish to set up my ppp login script so that it asks the client +# for the label they wish to use. I may only want user ``dodgy'' to access +# their own label in direct mode: +# +dodgy: + allow user dodgy + allow mode direct +# +# We don't want certain packets to keep our connection alive +# + set filter alive 0 deny udp src eq 520 # routed + set filter alive 1 deny udp dst eq 520 # routed + set filter alive 2 deny udp src eq 513 # rwhod + set filter alive 3 deny udp src eq 525 # timed + set filter alive 4 deny udp src eq 137 # NetBIOS name service + set filter alive 5 deny udp src eq 138 # NetBIOS datagram service + set filter alive 6 deny tcp src eq 139 # NetBIOS session service + set filter alive 7 deny udp dst eq 137 # NetBIOS name service + set filter alive 8 deny udp dst eq 138 # NetBIOS datagram service + set filter alive 9 deny tcp dst eq 139 # NetBIOS session service + set filter alive 10 deny 0/0 MYADDR icmp # Ping to us from outside + set filter alive 11 permit 0/0 0/0 +# +# And in auto mode, we don't want certain packets to cause a dialup +# + set filter dial 0 deny udp src eq 513 # rwhod + set filter dial 1 deny udp src eq 525 # timed + set filter dial 2 deny udp src eq 137 # NetBIOS name service + set filter dial 3 deny udp src eq 138 # NetBIOS datagram service + set filter dial 4 deny tcp src eq 139 # NetBIOS session service + set filter dial 5 deny udp dst eq 137 # NetBIOS name service + set filter dial 6 deny udp dst eq 138 # NetBIOS datagram service + set filter dial 7 deny tcp dst eq 139 # NetBIOS session service + set filter dial 8 deny tcp finrst # Badly closed TCP channels + set filter dial 9 permit 0 0 +# +# Once the line's up, allow these connections +# + set filter in 0 permit tcp dst eq 113 # ident + set filter out 0 permit tcp src eq 113 # ident + set filter in 1 permit tcp src eq 23 estab # telnet + set filter out 1 permit tcp dst eq 23 # telnet + set filter in 2 permit tcp src eq 21 estab # ftp + set filter out 2 permit tcp dst eq 21 # ftp + set filter in 3 permit tcp src eq 20 dst gt 1023 # ftp-data + set filter out 3 permit tcp dst eq 20 # ftp-data + set filter in 4 permit udp src eq 53 # DNS + set filter out 4 permit udp dst eq 53 # DNS + set filter in 5 permit 192.244.191.0/24 0/0 # Where I work + set filter out 5 permit 0/0 192.244.191.0/24 # Where I work + set filter in 6 permit icmp # pings + set filter out 6 permit icmp # pings + set filter in 7 permit udp dst gt 33433 # traceroute + set filter out 7 permit udp dst gt 33433 # traceroute + +# +# ``dodgynet'' is an example intended for an autodial configuration which +# is connecting a local network to a host on an untrusted network. +dodgynet: + set log Phase # Log link uptime + allow mode auto # For autoconnect only + set device /dev/cuau1 # Define modem device and speed + set speed 115200 + deny lqr # Don't support LQR + set phone 0W1194 # Remote system phone number, + set authname "pppLogin" # login + set authkey "MyPassword" # and password + set dial "ABORT BUSY ABORT NO\\sCARRIER \ # Chat script to dial the peer + TIMEOUT 5 \"\" ATZ OK-ATZ-OK \ + ATE1Q0M0 OK \\dATDT\\T \ + TIMEOUT 40 CONNECT" + set login "TIMEOUT 10 \"\" \"\" \ # And to login to remote system + gin:--gin: \\U word: \\P" + + # Drop the link after 15 minutes of inactivity + # Inactivity is defined by the `set filter alive' line below + set timeout 900 + + # Hard-code remote system to appear within local subnet and use proxy arp + # to make this system the gateway for the rest of the local network + set ifaddr 172.17.20.247 172.17.20.248 255.255.240.0 + enable proxy + + # Allow any TCP packet to keep the link alive + set filter alive 0 permit tcp + + # Only allow dialup to be triggered by http, rlogin, rsh, telnet, ftp or + # private TCP ports 24 and 4000 + set filter dial 0 7 0 0 tcp dst eq http + set filter dial 1 7 0 0 tcp dst eq login + set filter dial 2 7 0 0 tcp dst eq shell + set filter dial 3 7 0 0 tcp dst eq telnet + set filter dial 4 7 0 0 tcp dst eq ftp + set filter dial 5 7 0 0 tcp dst eq 24 + set filter dial 6 deny ! 0 0 tcp dst eq 4000 + + # From hosts on a couple of local subnets to the remote peer + # If the remote host allowed IP forwarding and we wanted to use it, the + # following rules could be split into two groups to separately validate + # the source and destination addresses. + set filter dial 7 permit 172.17.16.0/20 172.17.20.248 + set filter dial 8 permit 172.17.36.0/22 172.17.20.248 + set filter dial 9 permit 172.17.118.0/26 172.17.20.248 + set filter dial 10 permit 10.123.5.0/24 172.17.20.248 + + # Once the link's up, limit outgoing access to the specified hosts + set filter out 0 4 172.17.16.0/20 172.17.20.248 + set filter out 1 4 172.17.36.0/22 172.17.20.248 + set filter out 2 4 172.17.118.0/26 172.17.20.248 + set filter out 3 deny ! 10.123.5.0/24 172.17.20.248 + + # Allow established TCP connections + set filter out 4 permit 0 0 tcp estab + + # And new connections to http, rlogin, rsh, telnet, ftp and ports + # 24 and 4000 + set filter out 5 permit 0 0 tcp dst eq http + set filter out 6 permit 0 0 tcp dst eq login + set filter out 7 permit 0 0 tcp dst eq shell + set filter out 8 permit 0 0 tcp dst eq telnet + set filter out 9 permit 0 0 tcp dst eq ftp + set filter out 10 permit 0 0 tcp dst eq 24 + set filter out 11 permit 0 0 tcp dst eq 4000 + + # And outgoing icmp + set filter out 12 permit 0 0 icmp + + # Once the link's up, limit incoming access to the specified hosts + set filter in 0 4 172.17.20.248 172.17.16.0/20 + set filter in 1 4 172.17.20.248 172.17.36.0/22 + set filter in 2 4 172.17.20.248 172.17.118.0/26 + set filter in 3 deny ! 172.17.20.248 10.123.5.0/24 + + # Established TCP connections and non-PASV FTP + set filter in 4 permit 0/0 0/0 tcp estab + set filter in 5 permit 0/0 0/0 tcp src eq 20 + + # Useful ICMP messages + set filter in 6 permit 0/0 0/0 icmp src eq 3 + set filter in 7 permit 0/0 0/0 icmp src eq 4 + set filter in 8 permit 0/0 0/0 icmp src eq 11 + set filter in 9 permit 0/0 0/0 icmp src eq 12 + + # Echo reply (local systems can ping the remote host) + set filter in 10 permit 0/0 0/0 icmp src eq 0 + + # And the remote host can ping the local gateway (only) + set filter in 11 permit 0/0 172.17.20.247 icmp src eq 8 + + +# Server side PPP +# +# If you want the remote system to authenticate itself, you must insist +# that the peer uses CHAP or PAP with the "enable" keyword. Both CHAP and +# PAP are disabled by default. You may enable either or both. If both +# are enabled, CHAP is requested first. If the client doesn't agree, PAP +# will then be requested. +# +# Note: If you use the getty/login process to authenticate users, you +# don't need to enable CHAP or PAP, but the user that has logged +# in *MUST* be a member of the ``network'' group (in /etc/group). +# +# Note: Chap80 and chap81 are Microsoft variations of standard chap (05). +# +# If you wish to allow any user in the passwd database ppp access, you +# can ``enable passwdauth'', but this will only work with PAP. +# +# When the peer authenticates itself, we use ppp.secret for verification +# (although refer to the ``set radius'' command below for an alternative). +# +# Note: We may supply a third field in ppp.secret specifying the IP +# address for that user, a fourth field to specify the +# ppp.link{up,down} label to use and a fifth field to specify +# callback characteristics. +# +# The easiest way to allow transparent LAN access to your dialin users +# is to assign them a number from your local LAN and tell ppp to make a +# ``proxy'' arp entry for them. In this example, we have a local LAN +# with IP numbers 10.0.0.1 - 10.0.0.99, and we assign numbers to our +# ppp clients between 10.0.0.100 and 10.0.0.199. It is possible to +# override the dynamic IP number with a static IP number specified in +# ppp.secret. +# +# Ppp is launched with: +# # ppp -direct server +# +server: + enable chap chap80 chap81 pap passwdauth + enable proxy + set ifaddr 10.0.0.1 10.0.0.100-10.0.0.199 + accept dns + +# Example of a RADIUS configuration: +# If there are one or more radius servers available, we can use them +# instead of the ppp.secret file. Simply put then in a radius +# configuration file (usually /etc/radius.conf) and give ppp the +# file name. +# Ppp will use the FRAMED characteristics supplied by the radius server +# to configure the link. + +radius-server: + load server # load in the server config from above + set radius /etc/radius.conf + + +# Example to connect using a null-modem cable: +# The important thing here is to allow the lqr packets on both sides. +# Without them enabled, we can't tell if the line's dropped - there +# should always be carrier on a direct connection. +# Here, the server sends lqr's every 10 seconds and quits if five in a +# row fail. +# +# Make sure you don't have "deny lqr" in your default: on the client ! +# If the peer denies LQR, we still send ECHO LQR packets at the given +# lqrperiod interval (ppp-style-pings). +# +direct-client: + set dial + set device /dev/cuau0 + set sp 115200 + set timeout 900 + set lqrperiod 10 + set log Phase Chat LQM + set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp HELLO" + set ifaddr 10.0.4.2 10.0.4.1 + enable lqr echo + accept lqr + +direct-server: + set timeout 0 + set lqrperiod 10 + set log Phase LQM + set ifaddr 10.0.4.1 10.0.4.2 + enable lqr echo + accept lqr + + +# Example to connect via compuserve +# Compuserve insists on 7 bits even parity during the chat phase. Modem +# parity is always reset to ``none'' after the link has been established. +# +compuserve: + set phone 1234567 + set parity even + set login "TIMEOUT 100 \"\" \"\" Name: CIS ID: 999999,9999/go:pppconnect \ + word: XXXXXXXX PPP" + set timeout 300 + set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0 + delete ALL + add default HISADDR + + +# Example for PPP over TCP. +# We assume that inetd on tcpsrv.mynet has been +# configured to run "ppp -direct tcp-server" when it gets a connection on +# port 1234 with an entry something like this in /etc/inetd.conf.: +# +# ppp stream tcp nowait root /usr/sbin/ppp ppp -direct tcp-server +# +# with this in /etc/services: +# +# ppp 6671/tcp +# +# Read the man page for further details. +# +# Note, we assume we're using a binary-clean connection. If something +# such as `rlogin' is involved, you may need to ``set escape 0xff'' +# +tcp-client: + set device tcpsrv.mynet:6671 + set dial + set login + set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0 + +tcp-server: + set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0 + + +# Using UDP is also possible with this in /etc/inetd.conf: +# +# ppp dgram udp wait root /usr/sbin/ppp ppp -direct udp-server +# +# and this in /etc/services: +# +# ppp 6671/udp +# +udp-client: + set device udpsrv.mynet:6671/udp + set dial + set login + set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0 + +udp-server: + set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0 + + +# Example for PPP testing. +# If you want to test ppp, do it through the loopback interface: +# +# Requires a line in /etc/services: +# ppploop 6671/tcp # loopback ppp daemon +# +# and a line in /etc/inetd.conf: +# ppploop stream tcp nowait root /usr/sbin/ppp ppp -direct inet-loop-in +# +inet-loop: + set timeout 0 + set log phase chat connect lcp ipcp command + set device localhost:ppploop + set dial + set login + set ifaddr 127.0.0.2 127.0.0.3 + set server /var/run/ppp/loop "" 0177 + +inet-loop-in: + set timeout 0 + set log phase lcp ipcp command + allow mode direct + +# Example of a VPN. +# If you're going to create a tunnel through a public network, your VPN +# should be set up something like this: +# +# You should already have set up ssh using ssh-agent & ssh-add. +# +sloop: + load inet-loop + # Passive mode allows ssh plenty of time to establish the connection + set openmode passive + set device "!ssh whatevermachine /usr/sbin/ppp -direct inet-loop-in" + + +# or a better VPN solution (which doesn't run IP over a reliable +# protocol like tcp) may be: +# +vpn-client: + set device udpsrv.mynet:1234/udp # PPP over UDP + set dial + set login + set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0 + disable deflate pred1 + deny deflate pred1 + enable MPPE # With encryption + accept MPPE + +vpn-server: + set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0 + disable deflate pred1 + deny deflate pred1 + enable MPPE + accept MPPE + enable chap81 # Required for MPPE + +# Example of non-PPP callback. +# If you wish to connect to a server that will dial back *without* using +# the ppp callback facility (rfc1570), take advantage of the fact that +# ppp doesn't look for carrier 'till `set login' is complete: +# +# Here, we expect the server to say DIALBACK then disconnect after +# we've authenticated ourselves. When this has happened, we wait +# 60 seconds for a RING. +# +# Note, it's important that we tell ppp not to expect carrier, otherwise +# we'll drop out at the ``NO CARRIER'' stage. +# +dialback: + set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" ATZ OK-ATZ-OK \ + ATDT\\T TIMEOUT 60 CONNECT" + set cd off + set login "TIMEOUT 5 ogin:--ogin: ppp word: ppp TIMEOUT 15 DIALBACK \ + \"\" NO\\sCARRIER \"\" TIMEOUT 60 RING ATA CONNECT" + +# Example of PPP callback. +# Alternatively, if the peer is using the PPP callback protocol, we're +# happy either with ``auth'' style callback where the server dials us +# back based on what we authenticate ourselves with, ``cbcp'' style +# callback (invented by Microsoft but not agreed by the IETF) where +# we negotiate callback *after* authentication or E.164 callback where +# we specify only a phone number. I would recommend only ``auth'' and/or +# ``cbcp'' callback methods. +# For ``cbcp'', we insist that we choose ``1234567'' as the number that +# the server must call back. +# +callback: + load pmdemand # load in the pmdemand config + set callback auth cbcp e.164 1234567 + set cbcp 1234567 + +# If we're running a ppp server that wants to only call back microsoft +# clients on numbers configured in /etc/ppp/ppp.secret (the 5th field): +# +callback-server: + load server + set callback cbcp + set cbcp + set log +cbcp + set redial 3 1 + set device /dev/cuau0 + set speed 115200 + set dial "TIMEOUT 10 \"\" AT OK-AT-OK ATDT\\T CONNECT" + +# Or if we want to allow authenticated clients to specify their own +# callback number: +# +callback-server-client-decides: + load callback-server + set cbcp * + +# Multilink mode is available (rfc1990). +# To enable multi-link capabilities, you must specify a MRRU. 1500 is +# a reasonable value. To create new links, use the ``clone'' command +# to duplicate an existing link. If you already have more than one +# link, you must specify which link you wish to run the command on via +# the ``link'' command. +# +# It's worth increasing your MTU and MRU slightly in multi-link mode to +# prevent full packets from being fragmented. +# +# You can now ``dial'' specific links, or even dial all links at the +# same time. The `dial' command may also be prefixed with a specific +# link that should do the dialing. +# +mloop: + load loop + set device /dev/cuau0 /dev/cuau1 /dev/cuau2 # Use any of these devices + set mode interactive + set mrru 1500 + set mru 1504 # Room for the MP header + clone 1 2 3 + link deflink remove + # dial + # link 2 dial + # link 3 dial + +mloop-in: + set timeout 0 # No idle timer + set log tun phase + allow mode direct + set mrru 1500 + set mru 1504 # Room for the MP header + +# User supplied authentication: +# It's possible to run ppp in the background while specifying a +# program to use to obtain authentication details on demand. +# This program would usually be a simple GUI that presents a +# prompt to a known user. The ``chap-auth'' program is supplied +# as an example (and requires tcl version 8.0). +# +CHAPprompt: + load PAPorCHAPpmdemand + set authkey !/usr/share/examples/ppp/chap-auth + +# It's possible to do the same sort of thing at the login prompt. +# Here, after sending ``brian'' in response to the ``name'' prompt, +# we're prompted with ``code:''. A window is then displayed on the +# ``keep:0.0'' display and the typed response is sent to the peer +# as the password. We then expect to see ``MTU'' and ``.'' in the +# servers response. +# +loginprompt: + load pmdemand + set authname "brian" + set login "ABORT NO\\sCARRIER TIMEOUT 15 \"\" \"\" name:--name: \\U \ + code: \"!/usr/share/examples/ppp/login-auth -display keep:0.0 \ + AUTHNAME\" MTU \\c ." + +# ppp supports ppp over ethernet (PPPoE). Beware, many PPP servers cache +# the MAC address that connects to them, making it impossible to switch +# your PPPoE connection between machines. +# +# The current implementation requires Netgraph, so it doesn't work with +# OpenBSD or NetBSD. +# +# The client should be something like this: +# +pppoe: + set device PPPoE:de0:pppoe-in + enable lqr echo + set cd 5 + set dial + set login + set redial 0 0 + +# And the server should be running +# +# /usr/libexec/pppoed -p pppoe-in fxp0 +# +# See rc.conf(5) +# +pppoe-in: + allow mode direct # Only for use on server-side + enable lqr echo proxy # Enable LQR and proxy-arp + enable chap pap passwdauth # Force client authentication + set ifaddr 10.0.0.1 10.0.0.100-10.0.0.199 # Hand out up to 100 IP numbers + accept dns # Allow DNS negotiation + +# It's possible to run ppp back-to-back with itself. This is useful +# for testing. +# +# When testing scalability and concurrency, the following profile might +# be used. +# +# Note, you'll have to make some other machine adjustments: +# +# o Bump maxusers in your kernel configuration to about 256 so that there +# are enough process table slots. +# o Bump system file descriptors with ``sysctl kern.maxfiles=20480''. You'll +# need 3 descriptors per ppp process (assuming no server socket). +# +# You can now create 2000 processes (1000 pairs) with: +# +# n=0 +# while [ $n -lt 1000 ]; do ppp -b loop; n=$(($n + 1)); done +# +# If you want to test concurrency, try using ``ppp -dd loop'' instead. +# +loop: + set timeout 0 + set log + set device "!ppp -direct loop-in" + set dial + set login + set ifaddr 10.0.1.1/0 10.0.10.1-10.0.19.255 + disable deflate pred1 mppe + deny deflate pred1 mppe + +loop-in: + set timeout 0 + set log + allow mode direct + set ifaddr 10.0.10.1/0 10.0.1.1-10.0.9.255 + disable deflate pred1 mppe + deny deflate pred1 mppe diff --git a/share/examples/ppp/ppp.conf.span-isp b/share/examples/ppp/ppp.conf.span-isp new file mode 100644 index 000000000000..b1c3a143c633 --- /dev/null +++ b/share/examples/ppp/ppp.conf.span-isp @@ -0,0 +1,193 @@ + +# This advanced ppp configuration file explains how to implement +# the following: +# +# ------------- ------------- ------------- +# | host1 | | host2 | | host3 | +# ------------- ------------- ------------- +# | | | +# |---------------------- LAN ----------------------| +# | +# ------------- +# | Gateway | +# ------------- +# | +# ----------------------------------- +# | | | | +# isp1 isp2 isp3 ispN +# | | | | +# ----------------------------------- +# | +# ------------ +# | Receiver | +# ------------ +# | +# Internet +# +# The connection is implemented so that any ISP connection can go down +# without loss of connectivity between the LAN and the Internet. It is +# of course also possible to shut down any link manually. +# +# There is a working example in ppp.*.span-isp.working that can be tested +# on a single machine ! +# +# +# Prerequisites: +# +# o The Receiver machine must be in the outside world and must be willing +# to accept a multilink ppp connection over UDP, assigning a routable IP +# number to the Gateway machine. This probably means that it must be +# a *BSD box as I know of no other ppp implementations that can use UDP +# as a transport. +# +# o The Receiver machine must be multi-homed with at least N+1 addresses +# where N is the maximun number of ISPs that you wish to use +# simultaneously. We assume the IP numbers to be RIP1, RIP2 ... RIPN. +# REAL-LOCAL-IP is the real IP number of the Receiver machine (and must +# not be the same as any of the RIP* numbers). +# +# o Both the Gateway and the Receiver machines must have several tun +# interfaces configured into the kernel (see below). +# +# o Both the Gateway and the Receiver machines must have the following +# entry in /etc/services: +# +# ppp 6671/udp +# +# The port number isn't important, but it must be consistent across +# machines. +# +# o The Receiver machine must have the following entry in +# /etc/inetd.conf: +# +# ppp dgram udp wait root /usr/sbin/ppp ppp -direct vpn-in +# +# Note: Because inetd ``wait''s for ppp to finish, a single ppp +# invocation receives all incoming packets. This creates +# havoc with LQR magic number checks, so LQR *must not* be +# enabled. +# Also, -direct invocations of ppp do sendto()s using the +# address that was last recvfrom()d. This means that the +# returning traffic is a bit unbalanced. Perhaps ppp should +# be smart enough to automatically clone an existing link +# when it detects a new incoming address.... tricky ! +# +# If you use ppp to connect to your ISPs, the isp* profiles shold be used, +# resulting in the vpn* profiles being called from ppp.linkup.span-isp. +# These invocations will bond together into a MP ppp invocation. +# +# If the link to your ISP is via another type of interface (cable modem +# etc), simply configure the interface with a netmask of 0xffffffff and +# add a route to RIPN via the interface address (no default). You can +# then start ppp using the vpn-nic label. +# +# The Receiver machine should have N tun interfaces (where N is the maximum +# number of ISPs that you wish to use simultaneously). The Gateway machine +# requires N interfaces plus an additional N interfaces (total 2 * N) if +# you're using ppp to talk to the ISPs. + +# Using ppp to connect to your ISPs (PPP over UDP over PPP): +# +# When we connect to our ISPs using ppp, we start the MP ppp invocation +# from ppp.linkup (see ppp.linkup.span-isp) for each link. We also remove +# the link from ppp.linkdown (see ppp.linkdown.span-isp). This is necessary +# because relying on our LQR strategy (dropping the link after 5 missing +# replies) is just too slow to be practical in this environment. +# +# This works because the MP invocations are smart enough to recognise that +# another process is already running and to pass the link over to that +# running version. +# +# Only the ISP links should be started manually. When they come up, they'll +# start the MP invocation. + +default: + set speed 115200 + set device /dev/cuau0 /dev/cuau1 /dev/cuau2 /dev/cuau3 + set dial "ABORT BUSY ABORT NO\\sCARRIER ABORT NO\\sDIAL\\sTONE TIMEOUT 4 \ + \"\" ATZ OK-ATZ-OK ATDT\\T TIMEOUT 60 CONNECT \\c \\n" + set login + set redial 3 5 + set timeout 0 + enable lqr echo + set lqrperiod 15 + +isp1: + set phone "1234567" + set authname "isp1name" + set authkey "isp1key" + add! RIP1/32 HISADDR + +isp2: + set phone "2345678" + set authname "isp2name" + set authkey "isp2key" + add! RIP2/32 HISADDR + +ispN: + set phone "3456789" + set authname "ispNname" + set authkey "ispNkey" + add! RIPN/32 HISADDR + + +# Our MP version of ppp. vpn is a generic label used by each of the +# other vpn invocations by envoking ppp with both labels (see +# ppp.linkup.span-isp). +# Each ``set device'' command tells ppp to use UDP packets destined for +# the given IP/port as the link (transport). The routing table will +# ensure that these UDP packets use the correct ISP connection. + +vpn: + set enddisc LABEL + set speed sync + set mrru 1500 + set mru 1504 # Room for the MP header + nat enable yes + set authname "vpnname" + set authkey "vpnkey" + add! default HISADDR + disable deflate pred1 lqr + deny deflate pred1 + +vpn1: + rename 1 + set device RIP1:ppp/udp + +vpn2: + rename 2 + set device RIP2:ppp/udp + +vpnN: + rename N + set device RIPN:ppp/udp + +vpn-nic: + load vpn + clone 1 2 N + link deflink rm + link 1 set device RIP1:ppp/udp + link 2 set device RIP2:ppp/udp + link N set device RIPN:ppp/udp + +# The Receiver profile is a bit more straight forward, as it doesn't need +# to get bogged down with sublinks. Replace REAL-ASSIGNED-IP with the +# IP number to be assigned to the Gateway machine. Replace REAL-LOCAL-IP +# with the real IP number of the Receiver machine. +# +# No other entries are required on the Receiver machine, and this entry +# is not required on the Gateway machine. The Receiver machine also +# requires the contents of ppp.secret.span-isp. +# +# Of course it's simple to assign an IP block to the client with a simple +# ``add'' command, and then have the client use those IP numbers on its +# LAN rather than using ``nat enable yes''. + +vpn-in: + set enddisc label + set speed sync + set mrru 1500 + set mru 1504 # Room for the MP header + enable chap + disable lqr + set ifaddr REAL-LOCAL-IP REAL-ASSIGNED-IP diff --git a/share/examples/ppp/ppp.conf.span-isp.working b/share/examples/ppp/ppp.conf.span-isp.working new file mode 100644 index 000000000000..312a1de4c401 --- /dev/null +++ b/share/examples/ppp/ppp.conf.span-isp.working @@ -0,0 +1,106 @@ + +# This is a working example of ppp.conf.span-isp that uses ppp connections +# to the same machine through 3 null-modem serial cables. +# +# cuaD03 <-> cuaD04 +# cuaD01 <-> cuaD06 +# cuaD00 <-> cuaD07 +# +# with gettys running on cuaD04, cuaD06 and cuaD07. The gettytab entry +# for these devices has a pp= capability that references a script that +# says: +# +# #! /bin/sh +# tty=$(tty) +# exec /usr/sbin/pppin -direct isp-in-${tty#${tty%?}} +# +# The whole thing is brought up with these commands: +# +# ppp -b isp1 +# ppp -b isp2 +# ppp -b isp3 +# +# Something rather strange happens here. +# If you connect to the vpn-in diagnostic socket with ``pppctl +# /var/run/ppp/vpn-in'' and do a ``show links'', only a single link shows up. +# If you connect to the vpn diagnostic socket (which is created in +# ppp.linkup.span-isp.working, you see three links. This is because inetd +# is told to ``wait'' for ppp to finish and the receiving ppp gets to +# handle all incoming packets on the first descriptor. +# +# This is why enabling LQR won't work - VPN-IN has magic number problems, +# fails to reply to LQRs and the VPN invocations end up shutting down. +# +# If anyone can come up with a better way of doing PPP over UDP I'd be +# interrested to hear it. Currently, the server doesn't connect() or +# bind().... but the client connect()s. Is there any other way ? +# +# Answers on a postcard please ! (to brian@Awfulhak.org) +# + +default: + set speed 115200 + set device /dev/cuaD00 /dev/cuaD01 /dev/cuaD03 + set dial + set login + set redial 3 5 + set timeout 0 + enable lqr echo + set lqrperiod 15 + +isp1: + set authname "isp1name" + set authkey "isp1key" + +isp2: + set authname "isp2name" + set authkey "isp2key" + +isp3: + set authname "isp3name" + set authkey "isp3key" + + +vpn: + set enddisc LABEL + set speed sync + set mrru 1500 + set mru 1504 # Room for the MP header + set authname "vpnname" + set authkey "vpnkey" + add! default HISADDR + disable deflate pred1 lqr + deny deflate pred1 + +vpn1: + rename 1 + set device 127.0.2.7:ppp/udp + +vpn2: + rename 2 + set device 127.0.2.6:ppp/udp + +vpn3: + rename 3 + set device 127.0.2.4:ppp/udp + + +vpn-in: + set enddisc label + set speed sync + set mrru 1500 + set mru 1504 # Room for the MP header + enable chap + disable lqr + set ifaddr 127.0.0.2 127.0.0.3 + set server /var/run/ppp/vpn-in "" 0177 + + +isp-in-7: + set ifaddr 127.0.2.7 127.0.3.7 + +isp-in-6: + set ifaddr 127.0.2.6 127.0.3.6 + +isp-in-4: + set ifaddr 127.0.2.4 127.0.3.4 diff --git a/share/examples/ppp/ppp.linkdown.sample b/share/examples/ppp/ppp.linkdown.sample new file mode 100644 index 000000000000..1507f8c7c543 --- /dev/null +++ b/share/examples/ppp/ppp.linkdown.sample @@ -0,0 +1,33 @@ +######################################################################### +# +# Example of ppp.linkdown file +# +# This file is checked when ppp closes a connection. +# ppp searches the labels in this file as follows: +# +# 1) The label that matches the IP number assigned to our side. +# +# 2) The label specified on the command line to ppp. +# +# 3) If no label has been found, use MYADDR if it exists. +# +# +# +######################################################################### + +# We don't really need to do much here. If we have notified a DNS +# of our temporary IP number, we may want to ``un-notify'' them. +# +# If you're into sound effects when the link goes down, you can run +# ``auplay'' (assuming NAS is installed and configured). +# +MYADDR: + !bg /usr/local/bin/auplay /etc/ppp/linkdown.au + +# If you're running ``ppp -auto -nat dynamic-nat-auto'', and are +# assigned a dynamic IP number by the peer, this may be worth while +# to keep the interface aliases to a minimum (see ``enable iface-alias'' +# in the man page): +# +dynamic-nat-auto: + iface clear diff --git a/share/examples/ppp/ppp.linkdown.span-isp b/share/examples/ppp/ppp.linkdown.span-isp new file mode 100644 index 000000000000..a9cdcfc8d488 --- /dev/null +++ b/share/examples/ppp/ppp.linkdown.span-isp @@ -0,0 +1,16 @@ + +# Refer to ppp.conf.span-isp for a description of what this file is for. +# This file is only required on the Gateway machine. + +# The ISP links start our MP version of ppp as they come up +isp1: + !bg pppctl /var/run/ppp/vpn link 1 close + +isp2: + !bg pppctl /var/run/ppp/vpn link 2 close + +ispN: + !bg pppctl /var/run/ppp/vpn link N close + +vpn: + set server none diff --git a/share/examples/ppp/ppp.linkdown.span-isp.working b/share/examples/ppp/ppp.linkdown.span-isp.working new file mode 100644 index 000000000000..29ce3924e95c --- /dev/null +++ b/share/examples/ppp/ppp.linkdown.span-isp.working @@ -0,0 +1,16 @@ + +# This is a working example of ppp.linkdown.span-isp that uses ppp connections +# to the same machine through 3 null-modem serial cables. + +# The ISP links start our MP version of ppp as they come up +isp1: + !bg pppctl /var/run/ppp/vpn link 1 close + +isp2: + !bg pppctl /var/run/ppp/vpn link 2 close + +isp3: + !bg pppctl /var/run/ppp/vpn link 3 close + +vpn: + set server none diff --git a/share/examples/ppp/ppp.linkup.sample b/share/examples/ppp/ppp.linkup.sample new file mode 100644 index 000000000000..bce44414e880 --- /dev/null +++ b/share/examples/ppp/ppp.linkup.sample @@ -0,0 +1,53 @@ +######################################################################### +# +# Example of ppp.linkup file +# +# This file is checked when ppp establishes a connection. +# ppp searches the labels in this file as follows: +# +# 1) The label that matches the IP number assigned to our side. +# +# 2) The label specified on the command line to ppp. +# +# 3) If no label has been found, use MYADDR if it exists. +# +# +# +######################################################################### + +# It is no longer necessary to re-add the default route here as our +# ppp.conf route is `sticky' (see the man page). +# If you're into sound effects when the link comes up, you can run +# ``auplay'' (assuming NAS is installed and configured). +# +MYADDR: + !bg /usr/X11R6/bin/auplay /etc/ppp/linkup.au + +# If we've got 192.244.176.32 as our address, then regard peer as a gateway +# to 192.244.176.0 network. This may also be done in ppp.conf instead. +# +192.244.176.32: + add 192.244.176.0 0 HISADDR + +# You may want to execute a script after connecting. This script can do +# nice things such as kick off "sendmail -q", "popclient my.isp" and +# "slurp -d news". It can be passed MYADDR, HISADDR and INTERFACE +# as arguments too - useful for informing a DNS of your assigned IP. +# +# NOTE: It's vital that you use ``!bg'' rather than ``!'' if the program +# you're running will take some time or will require network +# connectivity. Using ``!'' will delay ppp 'till the completion +# of the program being run! +# +# You may also want some sound effects.... +# +pmdemand: + !bg /etc/ppp/ppp.etherup.pmdemand + ! sh -c "cat /etc/ppp/linkup.au >/dev/audio" + +# If your minimum call charge is 5 minutes, you may as well stay on +# the line for that amount of time. If we want a 60 second subsequent +# timeout, set your timeout to 300 in ppp.conf and then do this: +# +min5minutes: + !bg sh -c "sleep 240; pppctl -p mypassword 3000 set timeout 60" diff --git a/share/examples/ppp/ppp.linkup.span-isp b/share/examples/ppp/ppp.linkup.span-isp new file mode 100644 index 000000000000..819604d7fd22 --- /dev/null +++ b/share/examples/ppp/ppp.linkup.span-isp @@ -0,0 +1,16 @@ + +# Refer to ppp.conf.span-isp for a description of what this file is for. +# This file is only required on the Gateway machine. + +# The ISP links start our MP version of ppp as they come up +isp1: + !bg ppp -background vpn1 vpn + +isp2: + !bg ppp -background vpn2 vpn + +ispN: + !bg ppp -background vpnN vpn + +vpn: + set server /var/run/ppp/vpn "" 0177 diff --git a/share/examples/ppp/ppp.linkup.span-isp.working b/share/examples/ppp/ppp.linkup.span-isp.working new file mode 100644 index 000000000000..6c451a94ba20 --- /dev/null +++ b/share/examples/ppp/ppp.linkup.span-isp.working @@ -0,0 +1,16 @@ + +# This is a working example of ppp.linkup.span-isp that uses ppp connections +# to the same machine through 3 null-modem serial cables. + +# The ISP links start our MP version of ppp as they come up +isp1: + !bg ppp -background vpn1 vpn + +isp2: + !bg ppp -background vpn2 vpn + +isp3: + !bg ppp -background vpn3 vpn + +vpn: + set server /var/run/ppp/vpn "" 0177 diff --git a/share/examples/ppp/ppp.secret.sample b/share/examples/ppp/ppp.secret.sample new file mode 100644 index 000000000000..8104872b0456 --- /dev/null +++ b/share/examples/ppp/ppp.secret.sample @@ -0,0 +1,40 @@ +################################################## +# +# Example of ppp.secret file +# +# This file is used to authenticate incoming connections. +# You must ``enable'' either PAP or CHAP in your ppp.conf file. +# The peer may then use any of the Authname/Authkey pairs listed. +# Additionally, if ``passwdauth'' is enabled and an entry isn't +# found in this file, the passwd(5) database is used. +# +# If the password is specified as "*", look it up in passwd(5). +# This doesn't work for CHAP connections as ppp must have access +# to the unencrypted password for CHAP. +# +# If an IP address or address range is given as the third field, it +# will be assigned to the peer. A ``*'' or an empty field may be +# used as a placeholder if you do not wish to override the IP +# address, but wish to specify further fields. +# +# If a label is given as the forth field, it is used when reading +# the ppp.linkup and ppp.linkdown files. A ``*'' or an empty field +# can be used as a placeholder if you do not wish to override the +# label, but wish to specify further fields. +# +# If a phone number or list of phone numbers is given as the fifth +# field, these numbers will be used to call back the client if +# ``auth'' or ``cbcp'' callback is enabled (see ``set callback''). +# A ``*'' specifies that the client must specify the number. +# +# +################################################## + +# Authname Authkey Peer's IP address Label Callback + +oscar OurSecretKey 192.2.18.34 +BigBird X4dWg9327 192.2.18.33/32 +fred * * fred +subnet * 192.2.18.35-192.2.18.70 subnet +admin * * * * +homeworker * * * 1234567 diff --git a/share/examples/ppp/ppp.secret.span-isp b/share/examples/ppp/ppp.secret.span-isp new file mode 100644 index 000000000000..480933753e84 --- /dev/null +++ b/share/examples/ppp/ppp.secret.span-isp @@ -0,0 +1,5 @@ + +# Refer to ppp.conf.span-isp for a description of what this file is for. +# This file is only required on the Receiver machine. + +vpnname vpnkey diff --git a/share/examples/ppp/ppp.secret.span-isp.working b/share/examples/ppp/ppp.secret.span-isp.working new file mode 100644 index 000000000000..8b76d1560812 --- /dev/null +++ b/share/examples/ppp/ppp.secret.span-isp.working @@ -0,0 +1,8 @@ + +# This is a working example of ppp.secret.span-isp that uses ppp connections +# to the same machine through 3 null-modem serial cables. + +isp1name isp1key +isp2name isp2key +isp3name isp3key +vpnname vpnkey diff --git a/share/examples/printing/diablo-if-net b/share/examples/printing/diablo-if-net new file mode 100644 index 000000000000..b2ba028f2343 --- /dev/null +++ b/share/examples/printing/diablo-if-net @@ -0,0 +1,7 @@ +#!/bin/sh +# +# diablo-if-net - Text filter for Diablo printer `scrivener' listening +# on port 5100. Installed in /usr/local/libexec/diablo-if-net +# + +exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100 diff --git a/share/examples/printing/hpdf b/share/examples/printing/hpdf new file mode 100644 index 000000000000..d03c3ac70dfd --- /dev/null +++ b/share/examples/printing/hpdf @@ -0,0 +1,59 @@ +#!/bin/sh +# +# hpdf - Print DVI data on HP/PCL printer +# Installed in /usr/local/libexec/hpdf + +PATH=/usr/local/bin:$PATH; export PATH + +# +# Define a function to clean up our temporary files. These exist +# in the current directory, which will be the spooling directory +# for the printer. +# +cleanup() { + rm -f hpdf$$.dvi +} + +# +# Define a function to handle fatal errors: print the given message +# and exit 2. Exiting with 2 tells LPD to do not try to reprint the +# job. +# +fatal() { + echo "$@" 1>&2 + cleanup + exit 2 +} + +# +# If user removes the job, LPD will send SIGINT, so trap SIGINT +# (and a few other signals) to clean up after ourselves. +# +trap cleanup 1 2 15 + +# +# Make sure we are not colliding with any existing files. +# +cleanup + +# +# Link the DVI input file to standard input (the file to print). +# +ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0" + +# +# Make LF = CR+LF +# +printf "\033&k2G" || fatal "Cannot initialize printer" + +# +# Convert and print. Return value from dvilj2p does not seem to be +# reliable, so we ignore it. +# +dvilj2p -M1 -q -e- dfhp$$.dvi + +# +# Clean up and exit +# +cleanup +exit 0 diff --git a/share/examples/printing/hpif b/share/examples/printing/hpif new file mode 100644 index 000000000000..69f1f34c55fd --- /dev/null +++ b/share/examples/printing/hpif @@ -0,0 +1,11 @@ +#!/bin/sh +# +# hpif - Simple text input filter for lpd for HP-PCL based printers +# Installed in /usr/local/libexec/hpif +# +# Simply copies stdin to stdout. Ignores all filter arguments. +# Tells printer to treat LF as CR+LF. Writes a form feed character +# after printing job. + +printf "\033&k2G" && cat && printf "\f" && exit 0 +exit 2 diff --git a/share/examples/printing/hpof b/share/examples/printing/hpof new file mode 100644 index 000000000000..691b07f95d16 --- /dev/null +++ b/share/examples/printing/hpof @@ -0,0 +1,8 @@ +#!/bin/sh +# +# hpof - Output filter for Hewlett Packard PCL-compatible printers +# Installed in /usr/local/libexec/hpof + + +printf "\033&k2G" || exit 2 +exec /usr/libexec/lpr/lpf diff --git a/share/examples/printing/hprf b/share/examples/printing/hprf new file mode 100644 index 000000000000..37ad583fd9e1 --- /dev/null +++ b/share/examples/printing/hprf @@ -0,0 +1,8 @@ +#!/bin/sh +# +# hprf - FORTRAN text filter for LaserJet 3si: +# Installed in /usr/local/libexec/hprf +# + +printf "\033&k2G" && fpr && printf "\f" && exit 0 +exit 2 diff --git a/share/examples/printing/hpvf b/share/examples/printing/hpvf new file mode 100644 index 000000000000..de892ef77008 --- /dev/null +++ b/share/examples/printing/hpvf @@ -0,0 +1,9 @@ +#!/bin/sh +# +# +# hpvf - Convert GIF files into HP/PCL, then print +# Installed in /usr/local/libexec/hpvf + +giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \ + && exit 0 \ + || exit 2 diff --git a/share/examples/printing/if-simple b/share/examples/printing/if-simple new file mode 100644 index 000000000000..7a5bf97ab38f --- /dev/null +++ b/share/examples/printing/if-simple @@ -0,0 +1,9 @@ +#!/bin/sh +# +# if-simple - Simple text input filter for lpd +# Installed in /usr/local/libexec/if-simple +# +# Simply copies stdin to stdout. Ignores all filter arguments. + +/bin/cat && exit 0 +exit 2 diff --git a/share/examples/printing/if-simpleX b/share/examples/printing/if-simpleX new file mode 100644 index 000000000000..c14b4a25d12b --- /dev/null +++ b/share/examples/printing/if-simpleX @@ -0,0 +1,10 @@ +#!/bin/sh +# +# if-simple - Simple text input filter for lpd +# Installed in /usr/local/libexec/if-simple +# +# Simply copies stdin to stdout. Ignores all filter arguments. +# Writes a form feed character (\f) after printing job. + +/bin/cat && printf "\f" && exit 0 +exit 2 diff --git a/share/examples/printing/ifhp b/share/examples/printing/ifhp new file mode 100644 index 000000000000..ace0fab4214b --- /dev/null +++ b/share/examples/printing/ifhp @@ -0,0 +1,32 @@ +#!/bin/sh +# +# ifhp - Print Ghostscript-simulated PostScript on a DesJet 500 +# Installed in /usr/local/libexec/hpif + +# +# Treat LF as CR+LF: +# +printf "\033&k2G" || exit 2 + +# +# Read first two characters of the file +# +read first_line +first_two_chars=`expr "$first_line" : '\(..\)'` + +if [ "$first_two_chars" = "%!" ]; then + # + # It is PostScript; use Ghostscript to scan-convert and print it + # + /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \ + && exit 0 + +else + # + # Plain text or HP/PCL, so just print it directly; print a form + # at the end to eject the last page. + # + echo "$first_line" && cat && printf "\f" && exit 0 +fi + +exit 2 diff --git a/share/examples/printing/make-ps-header b/share/examples/printing/make-ps-header new file mode 100644 index 000000000000..19e38ab7c779 --- /dev/null +++ b/share/examples/printing/make-ps-header @@ -0,0 +1,79 @@ +#!/bin/sh +# +# make-ps-header - make a PostScript header page on stdout +# Installed in /usr/local/libexec/make-ps-header +# + +# +# These are PostScript units (72 to the inch). Modify for A4 or +# whatever size paper you are using: +# +page_width=612 +page_height=792 +border=72 + +# +# Check arguments +# +if [ $# -ne 3 ]; then + echo "Usage: `basename $0` <user> <host> <job>" 1>&2 + exit 1 +fi + +# +# Save these, mostly for readability in the PostScript, below. +# +user=$1 +host=$2 +job=$3 +date=`date` + +# +# Send the PostScript code to stdout. +# +exec cat <<EOF +%!PS + +% +% Make sure we do not interfere with user's job that will follow +% +save + +% +% Make a thick, unpleasant border around the edge of the paper. +% +$border $border moveto +$page_width $border 2 mul sub 0 rlineto +0 $page_height $border 2 mul sub rlineto +currentscreen 3 -1 roll pop 100 3 1 roll setscreen +$border 2 mul $page_width sub 0 rlineto closepath +0.8 setgray 10 setlinewidth stroke 0 setgray + +% +% Display user's login name, nice and large and prominent +% +/Helvetica-Bold findfont 64 scalefont setfont +$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto +($user) show + +% +% Now show the boring particulars +% +/Helvetica findfont 14 scalefont setfont +/y 200 def +[ (Job:) (Host:) (Date:) ] { + 200 y moveto show /y y 18 sub def +} forall + +/Helvetica-Bold findfont 14 scalefont setfont +/y 200 def +[ ($job) ($host) ($date) ] { + 270 y moveto show /y y 18 sub def +} forall + +% +% That is it +% +restore +showpage +EOF diff --git a/share/examples/printing/netprint b/share/examples/printing/netprint new file mode 100644 index 000000000000..9b5010cc8cc5 --- /dev/null +++ b/share/examples/printing/netprint @@ -0,0 +1,24 @@ +#!/usr/bin/perl +# +# netprint - Text filter for printer attached to network +# Installed in /usr/local/libexec/netprint +# + +$#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>"; + +$printer_host = $ARGV[0]; +$printer_port = $ARGV[1]; + +require 'sys/socket.ph'; + +($ignore, $ignore, $protocol) = getprotobyname('tcp'); +($ignore, $ignore, $ignore, $ignore, $address) + = gethostbyname($printer_host); + +$sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address); + +socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol) + || die "Can't create TCP/IP stream socket: $!"; +connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!"; +while (<STDIN>) { print PRINTER; } +exit 0; diff --git a/share/examples/printing/psdf b/share/examples/printing/psdf new file mode 100644 index 000000000000..e0d429b953c2 --- /dev/null +++ b/share/examples/printing/psdf @@ -0,0 +1,8 @@ +#!bin/sh +# +# psdf - DVI to PostScript printer filter +# Installed in /usr/local/libexec/psdf +# +# Invoked by lpd when user runs lpr -d +# +exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@" diff --git a/share/examples/printing/psdfX b/share/examples/printing/psdfX new file mode 100644 index 000000000000..43bdc4100bdb --- /dev/null +++ b/share/examples/printing/psdfX @@ -0,0 +1,31 @@ +#!/bin/sh +# +# psdf - DVI to PostScript printer filter +# Installed in /usr/local/libexec/psdf +# +# Invoked by lpd when user runs lpr -d +# + +orig_args="$@" + +fail() { + echo "$@" 1>&2 + exit 2 +} + +while getopts "x:y:n:h:" option; do + case $option in + x|y) ;; # Ignore + n) login=$OPTARG ;; + h) host=$OPTARG ;; + *) echo "LPD started `basename $0` wrong." 1>&2 + exit 2 + ;; + esac +done + +[ "$login" ] || fail "No login name" +[ "$host" ] || fail "No host name" + +( /u/kelly/freebsd/printing/filters/make-ps-header $login $host "DVI File" + /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args diff --git a/share/examples/printing/psif b/share/examples/printing/psif new file mode 100644 index 000000000000..1a816f64888b --- /dev/null +++ b/share/examples/printing/psif @@ -0,0 +1,23 @@ +#!/bin/sh +# +# psif - Print PostScript or plain text on a PostScript printer +# Script version; NOT the version that comes with lprps +# Installed in /usr/local/libexec/psif +# + +read first_line +first_two_chars=`expr "$first_line" : '\(..\)'` + +if [ "$first_two_chars" = "%!" ]; then + # + # PostScript job, print it. + # + echo "$first_line" && cat && printf "\004" && exit 0 + exit 2 +else + # + # Plain text, convert it, then print it. + # + ( echo "$first_line"; cat ) | /usr/local/bin/textps && printf "\004" && exit 0 + exit 2 +fi diff --git a/share/examples/printing/pstf b/share/examples/printing/pstf new file mode 100644 index 000000000000..308adc19e2ab --- /dev/null +++ b/share/examples/printing/pstf @@ -0,0 +1,6 @@ +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops | /usr/local/libexec/lprps "$@" diff --git a/share/examples/printing/pstfX b/share/examples/printing/pstfX new file mode 100644 index 000000000000..1af7134223c2 --- /dev/null +++ b/share/examples/printing/pstfX @@ -0,0 +1,6 @@ +#!/bin/sh +# +# pstf - Convert groff's troff data into PS, then print. +# Installed in /usr/local/libexec/pstf +# +exec grops diff --git a/share/examples/scsi_target/Makefile b/share/examples/scsi_target/Makefile new file mode 100644 index 000000000000..39950b8c0ac1 --- /dev/null +++ b/share/examples/scsi_target/Makefile @@ -0,0 +1,11 @@ + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/${PROG} +PROG= scsi_target +SRCS= scsi_target.h scsi_target.c scsi_cmds.c +DPADD= ${LIBCAM} ${LIBSBUF} +LDADD= -lcam -lsbuf + +MAN= scsi_target.8 + +.include <bsd.prog.mk> diff --git a/share/examples/scsi_target/scsi_cmds.c b/share/examples/scsi_target/scsi_cmds.c new file mode 100644 index 000000000000..43217a562aba --- /dev/null +++ b/share/examples/scsi_target/scsi_cmds.c @@ -0,0 +1,813 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * SCSI Disk Emulator + * + * Copyright (c) 2002 Nate Lawson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stddef.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <aio.h> +#include <unistd.h> +#include <assert.h> +#include <sys/param.h> +#include <sys/types.h> + +#include <cam/cam.h> +#include <cam/cam_ccb.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_targetio.h> +#include "scsi_target.h" + +typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *); +typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *, + io_ops); +#ifndef REPORT_LUNS +#define REPORT_LUNS 0xa0 +#endif + +struct targ_cdb_handlers { + u_int8_t cmd; + targ_start_func *start; + targ_done_func *done; +#define ILLEGAL_CDB 0xFF +}; + +static targ_start_func tcmd_inquiry; +static targ_start_func tcmd_req_sense; +static targ_start_func tcmd_rd_cap; +#ifdef READ_16 +static targ_start_func tcmd_rd_cap16; +#endif +static targ_start_func tcmd_rdwr; +static targ_start_func tcmd_rdwr_decode; +static targ_done_func tcmd_rdwr_done; +static targ_start_func tcmd_null_ok; +static targ_start_func tcmd_illegal_req; +static int start_io(struct ccb_accept_tio *atio, + struct ccb_scsiio *ctio, int dir); +static int init_inquiry(u_int16_t req_flags, u_int16_t sim_flags); +static struct initiator_state * + tcmd_get_istate(u_int init_id); +static void cdb_debug(u_int8_t *cdb, const char *msg, ...); + +static struct targ_cdb_handlers cdb_handlers[] = { + { READ_10, tcmd_rdwr, tcmd_rdwr_done }, + { WRITE_10, tcmd_rdwr, tcmd_rdwr_done }, + { READ_6, tcmd_rdwr, tcmd_rdwr_done }, + { WRITE_6, tcmd_rdwr, tcmd_rdwr_done }, + { INQUIRY, tcmd_inquiry, NULL }, + { REQUEST_SENSE, tcmd_req_sense, NULL }, + { READ_CAPACITY, tcmd_rd_cap, NULL }, + { TEST_UNIT_READY, tcmd_null_ok, NULL }, + { START_STOP_UNIT, tcmd_null_ok, NULL }, + { SYNCHRONIZE_CACHE, tcmd_null_ok, NULL }, + { MODE_SENSE_6, tcmd_illegal_req, NULL }, + { MODE_SELECT_6, tcmd_illegal_req, NULL }, + { REPORT_LUNS, tcmd_illegal_req, NULL }, +#ifdef READ_16 + { READ_16, tcmd_rdwr, tcmd_rdwr_done }, + { WRITE_16, tcmd_rdwr, tcmd_rdwr_done }, + { SERVICE_ACTION_IN, tcmd_rd_cap16, NULL }, +#endif + { ILLEGAL_CDB, NULL, NULL } +}; + +static struct scsi_inquiry_data inq_data; +static struct initiator_state istates[MAX_INITIATORS]; +extern int debug; +extern off_t volume_size; +extern u_int sector_size; +extern size_t buf_size; + +cam_status +tcmd_init(u_int16_t req_inq_flags, u_int16_t sim_inq_flags) +{ + struct initiator_state *istate; + int i, ret; + + /* Initialize our inquiry data */ + ret = init_inquiry(req_inq_flags, sim_inq_flags); + if (ret != 0) + return (ret); + + /* We start out life with a UA to indicate power-on/reset. */ + for (i = 0; i < MAX_INITIATORS; i++) { + istate = tcmd_get_istate(i); + bzero(istate, sizeof(*istate)); + istate->pending_ua = UA_POWER_ON; + } + + return (0); +} + +/* Caller allocates CTIO, sets its init_id +return 0 if done, 1 if more processing needed +on 0, caller sets SEND_STATUS */ +int +tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event) +{ + static struct targ_cdb_handlers *last_cmd; + struct initiator_state *istate; + struct atio_descr *a_descr; + int ret; + + if (debug) { + warnx("tcmd_handle atio %p ctio %p atioflags %#x", atio, ctio, + atio->ccb_h.flags); + } + ret = 0; + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + + /* Do a full lookup if one-behind cache failed */ + if (last_cmd == NULL || last_cmd->cmd != a_descr->cdb[0]) { + struct targ_cdb_handlers *h; + + for (h = cdb_handlers; h->cmd != ILLEGAL_CDB; h++) { + if (a_descr->cdb[0] == h->cmd) + break; + } + last_cmd = h; + } + + /* call completion and exit */ + if (event != ATIO_WORK) { + if (last_cmd->done != NULL) + last_cmd->done(atio, ctio, event); + else + free_ccb((union ccb *)ctio); + return (1); + } + + if (last_cmd->cmd == ILLEGAL_CDB) { + if (event != ATIO_WORK) { + warnx("no done func for %#x???", a_descr->cdb[0]); + abort(); + } + /* Not found, return illegal request */ + warnx("cdb %#x not handled", a_descr->cdb[0]); + tcmd_illegal_req(atio, ctio); + send_ccb((union ccb *)ctio, /*priority*/1); + return (0); + } + + istate = tcmd_get_istate(ctio->init_id); + if (istate == NULL) { + tcmd_illegal_req(atio, ctio); + send_ccb((union ccb *)ctio, /*priority*/1); + return (0); + } + + if (istate->pending_ca == 0 && istate->pending_ua != 0 && + a_descr->cdb[0] != INQUIRY) { + tcmd_sense(ctio->init_id, ctio, SSD_KEY_UNIT_ATTENTION, + 0x29, istate->pending_ua == UA_POWER_ON ? 1 : 2); + istate->pending_ca = CA_UNIT_ATTN; + if (debug) { + cdb_debug(a_descr->cdb, "UA active for %u: ", + atio->init_id); + } + send_ccb((union ccb *)ctio, /*priority*/1); + return (0); + } + + /* Store current CA and UA for later */ + istate->orig_ua = istate->pending_ua; + istate->orig_ca = istate->pending_ca; + + /* + * As per SAM2, any command that occurs + * after a CA is reported, clears the CA. We must + * also clear the UA condition, if any, that caused + * the CA to occur assuming the UA is not for a + * persistent condition. + */ + istate->pending_ca = CA_NONE; + if (istate->orig_ca == CA_UNIT_ATTN) + istate->pending_ua = UA_NONE; + + /* If we have a valid handler, call start or completion function */ + if (last_cmd->cmd != ILLEGAL_CDB) { + ret = last_cmd->start(atio, ctio); + /* XXX hack */ + if (last_cmd->start != tcmd_rdwr) { + a_descr->init_req += ctio->dxfer_len; + send_ccb((union ccb *)ctio, /*priority*/1); + } + } + + return (ret); +} + +static struct initiator_state * +tcmd_get_istate(u_int init_id) +{ + if (init_id >= MAX_INITIATORS) { + warnx("illegal init_id %d, max %d", init_id, MAX_INITIATORS - 1); + return (NULL); + } else { + return (&istates[init_id]); + } +} + +void +tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags, + u_int8_t asc, u_int8_t ascq) +{ + struct initiator_state *istate; + struct scsi_sense_data_fixed *sense; + + /* Set our initiator's istate */ + istate = tcmd_get_istate(init_id); + if (istate == NULL) + return; + istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */ + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; + bzero(sense, sizeof(*sense)); + sense->error_code = SSD_CURRENT_ERROR; + sense->flags = flags; + sense->add_sense_code = asc; + sense->add_sense_code_qual = ascq; + sense->extra_len = + offsetof(struct scsi_sense_data_fixed, sense_key_spec[2]) - + offsetof(struct scsi_sense_data_fixed, extra_len); + + /* Fill out the supplied CTIO */ + if (ctio != NULL) { + bcopy(sense, &ctio->sense_data, sizeof(*sense)); + ctio->sense_len = sizeof(*sense); /* XXX */ + ctio->ccb_h.flags &= ~CAM_DIR_MASK; + ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE | + CAM_SEND_STATUS; + ctio->dxfer_len = 0; + ctio->scsi_status = SCSI_STATUS_CHECK_COND; + } +} + +void +tcmd_ua(u_int init_id, ua_types new_ua) +{ + struct initiator_state *istate; + u_int start, end; + + if (init_id == CAM_TARGET_WILDCARD) { + start = 0; + end = MAX_INITIATORS - 1; + } else { + start = end = init_id; + } + + for (; start <= end; start++) { + istate = tcmd_get_istate(start); + if (istate == NULL) + break; + istate->pending_ua = new_ua; + } +} + +static int +tcmd_inquiry(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct scsi_inquiry *inq; + struct atio_descr *a_descr; + struct initiator_state *istate; + struct scsi_sense_data_fixed *sense; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + inq = (struct scsi_inquiry *)a_descr->cdb; + + if (debug) + cdb_debug(a_descr->cdb, "INQUIRY from %u: ", atio->init_id); + /* + * Validate the command. We don't support any VPD pages, so + * complain if EVPD or CMDDT is set. + */ + istate = tcmd_get_istate(ctio->init_id); + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; + if ((inq->byte2 & SI_EVPD) != 0) { + tcmd_illegal_req(atio, ctio); + sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD | + SSD_BITPTR_VALID | /*bit value*/1; + sense->sense_key_spec[1] = 0; + sense->sense_key_spec[2] = + offsetof(struct scsi_inquiry, byte2); + } else if (inq->page_code != 0) { + tcmd_illegal_req(atio, ctio); + sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD; + sense->sense_key_spec[1] = 0; + sense->sense_key_spec[2] = + offsetof(struct scsi_inquiry, page_code); + } else { + bcopy(&inq_data, ctio->data_ptr, sizeof(inq_data)); + ctio->dxfer_len = inq_data.additional_length + 4; + ctio->dxfer_len = min(ctio->dxfer_len, + scsi_2btoul(inq->length)); + ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + } + return (0); +} + +/* Initialize the inquiry response structure with the requested flags */ +static int +init_inquiry(u_int16_t req_flags, u_int16_t sim_flags) +{ + struct scsi_inquiry_data *inq; + + inq = &inq_data; + bzero(inq, sizeof(*inq)); + inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5); +#ifdef SCSI_REV_SPC + inq->version = SCSI_REV_SPC; /* was 2 */ +#else + inq->version = SCSI_REV_3; /* was 2 */ +#endif + + /* + * XXX cpi.hba_inquiry doesn't support Addr16 so we give the + * user what they want if they ask for it. + */ + if ((req_flags & SID_Addr16) != 0) { + sim_flags |= SID_Addr16; + warnx("Not sure SIM supports Addr16 but enabling it anyway"); + } + + /* Advertise only what the SIM can actually support */ + req_flags &= sim_flags; + scsi_ulto2b(req_flags, &inq->spc2_flags); + + inq->response_format = 2; /* SCSI2 Inquiry Format */ + inq->additional_length = SHORT_INQUIRY_LENGTH - + offsetof(struct scsi_inquiry_data, additional_length); + bcopy("FreeBSD ", inq->vendor, SID_VENDOR_SIZE); + bcopy("Emulated Disk ", inq->product, SID_PRODUCT_SIZE); + bcopy("0.1 ", inq->revision, SID_REVISION_SIZE); + return (0); +} + +static int +tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct scsi_request_sense *rsense; + struct scsi_sense_data_fixed *sense; + struct initiator_state *istate; + size_t dlen; + struct atio_descr *a_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + rsense = (struct scsi_request_sense *)a_descr->cdb; + + istate = tcmd_get_istate(ctio->init_id); + sense = (struct scsi_sense_data_fixed *)&istate->sense_data; + + if (debug) { + cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id); + warnx("Sending sense: %#x %#x %#x", sense->flags, + sense->add_sense_code, sense->add_sense_code_qual); + } + + if (istate->orig_ca == 0) { + tcmd_sense(ctio->init_id, NULL, SSD_KEY_NO_SENSE, 0, 0); + warnx("REQUEST SENSE from %u but no pending CA!", + ctio->init_id); + } + + bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data)); + dlen = offsetof(struct scsi_sense_data_fixed, extra_len) + + sense->extra_len + 1; + ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length)); + ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + return (0); +} + +static int +tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct scsi_read_capacity_data *srp; + struct atio_descr *a_descr; + uint32_t vsize; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + srp = (struct scsi_read_capacity_data *)ctio->data_ptr; + + if (volume_size > 0xffffffff) + vsize = 0xffffffff; + else + vsize = (uint32_t)(volume_size - 1); + + if (debug) { + cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ", + atio->init_id, vsize, sector_size); + } + + bzero(srp, sizeof(*srp)); + scsi_ulto4b(vsize, srp->addr); + scsi_ulto4b(sector_size, srp->length); + + ctio->dxfer_len = sizeof(*srp); + ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + return (0); +} + +#ifdef READ_16 +static int +tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct scsi_read_capacity_16 *scsi_cmd; + struct scsi_read_capacity_data_long *srp; + struct atio_descr *a_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb; + srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr; + + if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) { + tcmd_illegal_req(atio, ctio); + return (0); + } + + if (debug) { + cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ", + atio->init_id, volume_size - 1, sector_size); + } + + bzero(srp, sizeof(*srp)); + scsi_u64to8b(volume_size - 1, srp->addr); + scsi_ulto4b(sector_size, srp->length); + + ctio->dxfer_len = sizeof(*srp); + ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + return (0); +} +#endif + +static int +tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + struct atio_descr *a_descr; + struct ctio_descr *c_descr; + int ret; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + + /* Command needs to be decoded */ + if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_BOTH) { + if (debug) + warnx("Calling rdwr_decode"); + ret = tcmd_rdwr_decode(atio, ctio); + if (ret == 0) { + send_ccb((union ccb *)ctio, /*priority*/1); + return (0); + } + } + ctio->ccb_h.flags |= a_descr->flags; + + /* Call appropriate work function */ + if ((a_descr->flags & CAM_DIR_IN) != 0) { + ret = start_io(atio, ctio, CAM_DIR_IN); + if (debug) + warnx("Starting %p DIR_IN @" OFF_FMT ":%u", + a_descr, c_descr->offset, a_descr->targ_req); + } else { + ret = start_io(atio, ctio, CAM_DIR_OUT); + if (debug) + warnx("Starting %p DIR_OUT @" OFF_FMT ":%u", + a_descr, c_descr->offset, a_descr->init_req); + } + + return (ret); +} + +static int +tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + uint64_t blkno; + uint32_t count; + struct atio_descr *a_descr; + u_int8_t *cdb; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + cdb = a_descr->cdb; + if (debug) + cdb_debug(cdb, "R/W from %u: ", atio->init_id); + + switch (cdb[0]) { + case READ_6: + case WRITE_6: + { + struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb; + blkno = scsi_3btoul(rw_6->addr); + count = rw_6->length; + break; + } + case READ_10: + case WRITE_10: + { + struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb; + blkno = scsi_4btoul(rw_10->addr); + count = scsi_2btoul(rw_10->length); + break; + } +#ifdef READ_16 + case READ_16: + case WRITE_16: + { + struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb; + blkno = scsi_8btou64(rw_16->addr); + count = scsi_4btoul(rw_16->length); + break; + } +#endif + default: + tcmd_illegal_req(atio, ctio); + return (0); + } + if (blkno + count > volume_size) { + warnx("Attempt to access past end of volume"); + tcmd_sense(ctio->init_id, ctio, + SSD_KEY_ILLEGAL_REQUEST, 0x21, 0); + return (0); + } + + /* Get an (overall) data length and set direction */ + a_descr->base_off = ((off_t)blkno) * sector_size; + a_descr->total_len = count * sector_size; + if (a_descr->total_len == 0) { + if (debug) + warnx("r/w 0 blocks @ blkno " OFF_FMT, blkno); + tcmd_null_ok(atio, ctio); + return (0); + } else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) { + a_descr->flags |= CAM_DIR_OUT; + if (debug) + warnx("write %u blocks @ blkno " OFF_FMT, count, blkno); + } else { + a_descr->flags |= CAM_DIR_IN; + if (debug) + warnx("read %u blocks @ blkno " OFF_FMT, count, blkno); + } + return (1); +} + +static int +start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir) +{ + struct atio_descr *a_descr; + struct ctio_descr *c_descr; + int ret; + + /* Set up common structures */ + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + + if (dir == CAM_DIR_IN) { + c_descr->offset = a_descr->base_off + a_descr->targ_req; + ctio->dxfer_len = a_descr->total_len - a_descr->targ_req; + } else { + c_descr->offset = a_descr->base_off + a_descr->init_req; + ctio->dxfer_len = a_descr->total_len - a_descr->init_req; + } + ctio->dxfer_len = min(ctio->dxfer_len, buf_size); + assert(ctio->dxfer_len >= 0); + + c_descr->aiocb.aio_offset = c_descr->offset; + c_descr->aiocb.aio_nbytes = ctio->dxfer_len; + + /* If DIR_IN, start read from target, otherwise begin CTIO xfer. */ + ret = 1; + if (dir == CAM_DIR_IN) { + if (notaio) { + if (debug) + warnx("read sync %lu @ block " OFF_FMT, + (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (lseek(c_descr->aiocb.aio_fildes, + c_descr->aiocb.aio_offset, SEEK_SET) < 0) { + perror("lseek"); + err(1, "lseek"); + } + if (read(c_descr->aiocb.aio_fildes, + (void *)c_descr->aiocb.aio_buf, + ctio->dxfer_len) != ctio->dxfer_len) { + err(1, "read"); + } + } else { + if (debug) + warnx("read async %lu @ block " OFF_FMT, + (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (aio_read(&c_descr->aiocb) < 0) { + err(1, "aio_read"); /* XXX */ + } + } + a_descr->targ_req += ctio->dxfer_len; + /* if we're done, we can mark the CCB as to send status */ + if (a_descr->targ_req == a_descr->total_len) { + ctio->ccb_h.flags |= CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + ret = 0; + } + if (notaio) + tcmd_rdwr_done(atio, ctio, AIO_DONE); + } else { + if (a_descr->targ_ack == a_descr->total_len) + tcmd_null_ok(atio, ctio); + a_descr->init_req += ctio->dxfer_len; + if (a_descr->init_req == a_descr->total_len && + ctio->dxfer_len > 0) { + /* + * If data phase done, remove atio from workq. + * The completion handler will call work_atio to + * send the final status. + */ + ret = 0; + } + send_ccb((union ccb *)ctio, /*priority*/1); + } + + return (ret); +} + +static void +tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, + io_ops event) +{ + struct atio_descr *a_descr; + struct ctio_descr *c_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + + switch (event) { + case AIO_DONE: + if (!notaio && aio_return(&c_descr->aiocb) < 0) { + warn("aio_return error"); + /* XXX */ + tcmd_sense(ctio->init_id, ctio, + SSD_KEY_MEDIUM_ERROR, 0, 0); + send_ccb((union ccb *)ctio, /*priority*/1); + break; + } + a_descr->targ_ack += ctio->dxfer_len; + if ((a_descr->flags & CAM_DIR_IN) != 0) { + if (debug) { + if (notaio) + warnx("sending CTIO for AIO read"); + else + warnx("sending CTIO for sync read"); + } + a_descr->init_req += ctio->dxfer_len; + send_ccb((union ccb *)ctio, /*priority*/1); + } else { + /* Use work function to send final status */ + if (a_descr->init_req == a_descr->total_len) + work_atio(atio); + if (debug) + warnx("AIO done freeing CTIO"); + free_ccb((union ccb *)ctio); + } + break; + case CTIO_DONE: + switch (ctio->ccb_h.status & CAM_STATUS_MASK) { + case CAM_REQ_CMP: + break; + case CAM_REQUEUE_REQ: + warnx("requeueing request"); + if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) { + if (aio_write(&c_descr->aiocb) < 0) { + err(1, "aio_write"); /* XXX */ + } + } else { + if (aio_read(&c_descr->aiocb) < 0) { + err(1, "aio_read"); /* XXX */ + } + } + return; + default: + errx(1, "CTIO failed, status %#x", ctio->ccb_h.status); + } + a_descr->init_ack += ctio->dxfer_len; + if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT && + ctio->dxfer_len > 0) { + a_descr->targ_req += ctio->dxfer_len; + if (notaio) { + if (debug) + warnx("write sync %lu @ block " + OFF_FMT, (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (lseek(c_descr->aiocb.aio_fildes, + c_descr->aiocb.aio_offset, SEEK_SET) < 0) { + perror("lseek"); + err(1, "lseek"); + } + if (write(c_descr->aiocb.aio_fildes, + (void *) c_descr->aiocb.aio_buf, + ctio->dxfer_len) != ctio->dxfer_len) { + err(1, "write"); + } + tcmd_rdwr_done(atio, ctio, AIO_DONE); + } else { + if (debug) + warnx("write async %lu @ block " + OFF_FMT, (unsigned long) + (ctio->dxfer_len / sector_size), + c_descr->offset / sector_size); + if (aio_write(&c_descr->aiocb) < 0) { + err(1, "aio_write"); /* XXX */ + } + } + } else { + if (debug) + warnx("CTIO done freeing CTIO"); + free_ccb((union ccb *)ctio); + } + break; + default: + warnx("Unknown completion code %d", event); + abort(); + /* NOTREACHED */ + } +} + +/* Simple ok message used by TUR, SYNC_CACHE, etc. */ +static int +tcmd_null_ok(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + if (debug) { + struct atio_descr *a_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + cdb_debug(a_descr->cdb, "Sending null ok to %u : ", atio->init_id); + } + + ctio->dxfer_len = 0; + ctio->ccb_h.flags &= ~CAM_DIR_MASK; + ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_STATUS; + ctio->scsi_status = SCSI_STATUS_OK; + return (0); +} + +/* Simple illegal request message used by MODE SENSE, etc. */ +static int +tcmd_illegal_req(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio) +{ + if (debug) { + struct atio_descr *a_descr; + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + cdb_debug(a_descr->cdb, "Sending ill req to %u: ", atio->init_id); + } + + tcmd_sense(atio->init_id, ctio, SSD_KEY_ILLEGAL_REQUEST, + /*asc*/0x24, /*ascq*/0); + return (0); +} + +static void +cdb_debug(u_int8_t *cdb, const char *msg, ...) +{ + char msg_buf[512]; + int len; + va_list ap; + + va_start(ap, msg); + vsnprintf(msg_buf, sizeof(msg_buf), msg, ap); + va_end(ap); + len = strlen(msg_buf); + scsi_cdb_string(cdb, msg_buf + len, sizeof(msg_buf) - len); + warnx("%s", msg_buf); +} diff --git a/share/examples/scsi_target/scsi_target.8 b/share/examples/scsi_target/scsi_target.8 new file mode 100644 index 000000000000..f3bcfac33ee8 --- /dev/null +++ b/share/examples/scsi_target/scsi_target.8 @@ -0,0 +1,156 @@ +.\" Copyright (c) 2002 +.\" Nate Lawson. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Nate Lawson AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 15, 2002 +.Dt SCSI_TARGET 8 +.Os +.Sh NAME +.Nm scsi_target +.Nd usermode SCSI disk emulator +.Sh SYNOPSIS +.Nm +.Op Fl AdST +.Op Fl b Ar size +.Op Fl c Ar size +.Op Fl s Ar size +.Op Fl W Ar num +.Ar bus : Ns Ar target : Ns Ar lun +.Ar filename +.Sh DESCRIPTION +The +.Nm +utility emulates a SCSI target device using the +.Xr targ 4 +device driver. +It supports the basic commands of a direct access device, like +.Xr da 4 . +In typical operation, it opens a control device and +enables target mode for the specified LUN. +It then communicates with +the SIM using CCBs exchanged via +.Xr read 2 +and +.Xr write 2 . +READ and WRITE CDBs are satisfied with the specified backing store file. +.Pp +For performance, all backing store accesses use +.Xr aio 4 . +Thus, +.Nm +requires a kernel compiled with +.Cd "options VFS_AIO" . +.Pp +Options: +.Bl -tag -width indent +.It Fl A +Enable 16 addresses if supported by the SIM. +Default is 8. +.It Fl S +Enable synchronous transfers if supported by the SIM. +Default is disabled. +.It Fl T +Enable tagged queuing if supported by the SIM. +Default is no tagged queuing. +.It Fl W Cm 8 | 16 | 32 +Enable 16 or 32 bit wide transfers if supported by the SIM. +Default is 8. +.It Fl b Ar bufsize +Set buffer size for transfers. +Transfers larger than this will be split into multiple transfers. +.It Fl c Ar sectorsize +Set sector size for emulated volume. +Default is 512. +.It Fl d +Enable debugging output in +.Nm +and its associated control device. +.It Fl s Ar volsize +Use a different size for the emulated volume. +Must be less than or equal to the size of +.Ar filename . +If the number ends with a +.Dq Li k , +.Dq Li m , +.Dq Li g , +.Dq Li t , +.Dq Li p , +or +.Dq Li e , +the number is multiplied by 2^10 (1K), 2^20 (1M), 2^30 (1G), 2^40 (1T), +2^50 (1P) and 2^60 (1E) +respectively. +.El +.Pp +Required arguments: +.Bl -tag -width indent +.It Ar bus : Ns Ar target : Ns Ar lun +Attach to specified bus ID, target ID, and LUN. +.It Ar filename +File to use as a backing store. +.El +.Pp +All options default to the minimal functionality of SCSI-1. +To be safe, +.Nm +checks the SIM for the requested capability before enabling target mode. +.Sh FILES +.Bl -tag -width ".Pa /usr/share/examples/scsi_target" -compact +.It Pa /dev/targ* +Control devices. +.It Pa /usr/share/examples/scsi_target +Source directory. +.El +.Sh EXAMPLES +Create a 5 megabyte backing store file. +.Pp +.Dl "dd if=/dev/zero of=vol size=1m count=5" +.Pp +Enable target mode on bus 0, target ID 1, LUN 0, using +.Pa vol +as the backing store for READ6/10 and WRITE6/10 commands. +Only the first 1000 bytes of +.Pa vol +will be used. +Debugging information will be output. +16-bit wide transfers will be used if the SIM supports them. +.Pp +.Dl "scsi_target -d -s 1000 -W 16 0:1:0 vol" +.Sh SEE ALSO +.Xr scsi 4 , +.Xr targ 4 +.Sh AUTHORS +.An -nosplit +The +.Nm +example first appeared in +.Fx 3.0 +and was written by +.An Justin T. Gibbs . +It was rewritten for +.Fx 5.0 +by +.An Nate Lawson Aq Mt nate@root.org . diff --git a/share/examples/scsi_target/scsi_target.c b/share/examples/scsi_target/scsi_target.c new file mode 100644 index 000000000000..b8f3ed6a8a81 --- /dev/null +++ b/share/examples/scsi_target/scsi_target.c @@ -0,0 +1,986 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * SCSI Disk Emulator + * + * Copyright (c) 2002 Nate Lawson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <ctype.h> +#include <errno.h> +#include <err.h> +#include <fcntl.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> +#include <aio.h> +#include <assert.h> +#include <sys/stat.h> +#include <sys/queue.h> +#include <sys/event.h> +#include <sys/param.h> +#include <sys/disk.h> +#include <cam/cam_queue.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_targetio.h> +#include <cam/scsi/scsi_message.h> +#include "scsi_target.h" + +/* Maximum amount to transfer per CTIO */ +#define MAX_XFER MAXPHYS +/* Maximum number of allocated CTIOs */ +#define MAX_CTIOS 64 +/* Maximum sector size for emulated volume */ +#define MAX_SECTOR 32768 + +/* Global variables */ +int debug; +int notaio = 0; +off_t volume_size; +u_int sector_size; +size_t buf_size; + +/* Local variables */ +static int targ_fd; +static int kq_fd; +static int file_fd; +static int num_ctios; +static struct ccb_queue pending_queue; +static struct ccb_queue work_queue; +static struct ioc_enable_lun ioc_enlun = { + CAM_BUS_WILDCARD, + CAM_TARGET_WILDCARD, + CAM_LUN_WILDCARD +}; + +/* Local functions */ +static void cleanup(void); +static int init_ccbs(void); +static void request_loop(void); +static void handle_read(void); +/* static int work_atio(struct ccb_accept_tio *); */ +static void queue_io(struct ccb_scsiio *); +static int run_queue(struct ccb_accept_tio *); +static int work_inot(struct ccb_immediate_notify *); +static struct ccb_scsiio * + get_ctio(void); +/* static void free_ccb(union ccb *); */ +static cam_status get_sim_flags(u_int16_t *); +static void rel_simq(void); +static void abort_all_pending(void); +static void usage(void); + +int +main(int argc, char *argv[]) +{ + int ch; + char *file_name; + u_int16_t req_flags, sim_flags; + off_t user_size; + + /* Initialize */ + debug = 0; + req_flags = sim_flags = 0; + user_size = 0; + targ_fd = file_fd = kq_fd = -1; + num_ctios = 0; + sector_size = SECTOR_SIZE; + buf_size = DFLTPHYS; + + /* Prepare resource pools */ + TAILQ_INIT(&pending_queue); + TAILQ_INIT(&work_queue); + + while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) { + switch(ch) { + case 'A': + req_flags |= SID_Addr16; + break; + case 'd': + debug = 1; + break; + case 'S': + req_flags |= SID_Sync; + break; + case 'T': + req_flags |= SID_CmdQue; + break; + case 'b': + buf_size = atoi(optarg); + if (buf_size < 256 || buf_size > MAX_XFER) + errx(1, "Unreasonable buf size: %s", optarg); + break; + case 'c': + sector_size = atoi(optarg); + if (sector_size < 512 || sector_size > MAX_SECTOR) + errx(1, "Unreasonable sector size: %s", optarg); + break; + case 's': + { + int last, shift = 0; + + last = strlen(optarg) - 1; + if (last > 0) { + switch (tolower(optarg[last])) { + case 'e': + shift += 10; + /* FALLTHROUGH */ + case 'p': + shift += 10; + /* FALLTHROUGH */ + case 't': + shift += 10; + /* FALLTHROUGH */ + case 'g': + shift += 10; + /* FALLTHROUGH */ + case 'm': + shift += 10; + /* FALLTHROUGH */ + case 'k': + shift += 10; + optarg[last] = 0; + break; + } + } + user_size = strtoll(optarg, (char **)NULL, /*base*/10); + user_size <<= shift; + if (user_size < 0) + errx(1, "Unreasonable volume size: %s", optarg); + break; + } + case 'W': + req_flags &= ~(SID_WBus16 | SID_WBus32); + switch (atoi(optarg)) { + case 8: + /* Leave req_flags zeroed */ + break; + case 16: + req_flags |= SID_WBus16; + break; + case 32: + req_flags |= SID_WBus32; + break; + default: + warnx("Width %s not supported", optarg); + usage(); + /* NOTREACHED */ + } + break; + case 'Y': + notaio = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 2) + usage(); + + sscanf(argv[0], "%u:%u:%u", &ioc_enlun.path_id, &ioc_enlun.target_id, + &ioc_enlun.lun_id); + file_name = argv[1]; + + if (ioc_enlun.path_id == CAM_BUS_WILDCARD || + ioc_enlun.target_id == CAM_TARGET_WILDCARD || + ioc_enlun.lun_id == CAM_LUN_WILDCARD) { + warnx("Incomplete target path specified"); + usage(); + /* NOTREACHED */ + } + /* We don't support any vendor-specific commands */ + ioc_enlun.grp6_len = 0; + ioc_enlun.grp7_len = 0; + + /* Open backing store for IO */ + file_fd = open(file_name, O_RDWR); + if (file_fd < 0) + errx(EX_NOINPUT, "open backing store file"); + + /* Check backing store size or use the size user gave us */ + if (user_size == 0) { + struct stat st; + + if (fstat(file_fd, &st) < 0) + err(1, "fstat file"); +#if __FreeBSD_version >= 500000 + if ((st.st_mode & S_IFCHR) != 0) { + /* raw device */ + off_t mediasize; + if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0) + err(1, "DIOCGMEDIASIZE"); + + /* XXX get sector size by ioctl()?? */ + volume_size = mediasize / sector_size; + } else +#endif + volume_size = st.st_size / sector_size; + } else { + volume_size = user_size / sector_size; + } + if (debug) + warnx("volume_size: %d bytes x " OFF_FMT " sectors", + sector_size, volume_size); + + if (volume_size <= 0) + errx(1, "volume must be larger than %d", sector_size); + + if (notaio == 0) { + struct aiocb aio, *aiop; + + /* See if we have we have working AIO support */ + memset(&aio, 0, sizeof(aio)); + aio.aio_buf = malloc(sector_size); + if (aio.aio_buf == NULL) + err(1, "malloc"); + aio.aio_fildes = file_fd; + aio.aio_offset = 0; + aio.aio_nbytes = sector_size; + signal(SIGSYS, SIG_IGN); + if (aio_read(&aio) != 0) { + printf("AIO support is not available- switchin to" + " single-threaded mode.\n"); + notaio = 1; + } else { + if (aio_waitcomplete(&aiop, NULL) != sector_size) + err(1, "aio_waitcomplete"); + assert(aiop == &aio); + signal(SIGSYS, SIG_DFL); + } + free((void *)aio.aio_buf); + if (debug && notaio == 0) + warnx("aio support tested ok"); + } + + targ_fd = open("/dev/targ", O_RDWR); + if (targ_fd < 0) + err(1, "/dev/targ"); + else + warnx("opened /dev/targ"); + + /* The first three are handled by kevent() later */ + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGPROF, SIG_IGN); + signal(SIGALRM, SIG_IGN); + signal(SIGSTOP, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + /* Register a cleanup handler to run when exiting */ + atexit(cleanup); + + /* Enable listening on the specified LUN */ + if (ioctl(targ_fd, TARGIOCENABLE, &ioc_enlun) != 0) + err(1, "TARGIOCENABLE"); + + /* Enable debugging if requested */ + if (debug) { + if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0) + warnx("TARGIOCDEBUG"); + } + + /* Set up inquiry data according to what SIM supports */ + if (get_sim_flags(&sim_flags) != CAM_REQ_CMP) + errx(1, "get_sim_flags"); + + if (tcmd_init(req_flags, sim_flags) != 0) + errx(1, "Initializing tcmd subsystem failed"); + + /* Queue ATIOs and INOTs on descriptor */ + if (init_ccbs() != 0) + errx(1, "init_ccbs failed"); + + if (debug) + warnx("main loop beginning"); + + request_loop(); + + exit(0); +} + +static void +cleanup() +{ + struct ccb_hdr *ccb_h; + + if (debug) { + warnx("cleanup called"); + debug = 0; + ioctl(targ_fd, TARGIOCDEBUG, &debug); + } + ioctl(targ_fd, TARGIOCDISABLE, NULL); + close(targ_fd); + + while ((ccb_h = TAILQ_FIRST(&pending_queue)) != NULL) { + TAILQ_REMOVE(&pending_queue, ccb_h, periph_links.tqe); + free_ccb((union ccb *)ccb_h); + } + while ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { + TAILQ_REMOVE(&work_queue, ccb_h, periph_links.tqe); + free_ccb((union ccb *)ccb_h); + } + + if (kq_fd != -1) + close(kq_fd); +} + +/* Allocate ATIOs/INOTs and queue on HBA */ +static int +init_ccbs() +{ + int i; + + for (i = 0; i < MAX_INITIATORS; i++) { + struct ccb_accept_tio *atio; + struct atio_descr *a_descr; + struct ccb_immediate_notify *inot; + + atio = (struct ccb_accept_tio *)malloc(sizeof(*atio)); + if (atio == NULL) { + warn("malloc ATIO"); + return (-1); + } + a_descr = (struct atio_descr *)malloc(sizeof(*a_descr)); + if (a_descr == NULL) { + free(atio); + warn("malloc atio_descr"); + return (-1); + } + atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO; + atio->ccb_h.targ_descr = a_descr; + send_ccb((union ccb *)atio, /*priority*/1); + + inot = (struct ccb_immediate_notify *)malloc(sizeof(*inot)); + if (inot == NULL) { + warn("malloc INOT"); + return (-1); + } + inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY; + send_ccb((union ccb *)inot, /*priority*/1); + } + + return (0); +} + +static void +request_loop() +{ + struct kevent events[MAX_EVENTS]; + struct timespec ts, *tptr; + int quit; + + /* Register kqueue for event notification */ + if ((kq_fd = kqueue()) < 0) + err(1, "init kqueue"); + + /* Set up some default events */ + EV_SET(&events[0], SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); + EV_SET(&events[1], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); + EV_SET(&events[2], SIGTERM, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0); + EV_SET(&events[3], targ_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0); + if (kevent(kq_fd, events, 4, NULL, 0, NULL) < 0) + err(1, "kevent signal registration"); + + ts.tv_sec = 0; + ts.tv_nsec = 0; + tptr = NULL; + quit = 0; + + /* Loop until user signal */ + while (quit == 0) { + int retval, i, oo; + struct ccb_hdr *ccb_h; + + /* Check for the next signal, read ready, or AIO completion */ + retval = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, tptr); + if (retval < 0) { + if (errno == EINTR) { + if (debug) + warnx("EINTR, looping"); + continue; + } + else { + err(1, "kevent failed"); + } + } else if (retval > MAX_EVENTS) { + errx(1, "kevent returned more events than allocated?"); + } + + /* Process all received events. */ + for (oo = i = 0; i < retval; i++) { + if ((events[i].flags & EV_ERROR) != 0) + errx(1, "kevent registration failed"); + + switch (events[i].filter) { + case EVFILT_READ: + if (debug) + warnx("read ready"); + handle_read(); + break; + case EVFILT_AIO: + { + struct ccb_scsiio *ctio; + struct ctio_descr *c_descr; + if (debug) + warnx("aio ready"); + + ctio = (struct ccb_scsiio *)events[i].udata; + c_descr = (struct ctio_descr *) + ctio->ccb_h.targ_descr; + c_descr->event = AIO_DONE; + /* Queue on the appropriate ATIO */ + queue_io(ctio); + /* Process any queued completions. */ + oo += run_queue(c_descr->atio); + break; + } + case EVFILT_SIGNAL: + if (debug) + warnx("signal ready, setting quit"); + quit = 1; + break; + default: + warnx("unknown event %d", events[i].filter); + break; + } + + if (debug) + warnx("event %d done", events[i].filter); + } + + if (oo) { + tptr = &ts; + continue; + } + + /* Grab the first CCB and perform one work unit. */ + if ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) { + union ccb *ccb; + + ccb = (union ccb *)ccb_h; + switch (ccb_h->func_code) { + case XPT_ACCEPT_TARGET_IO: + /* Start one more transfer. */ + retval = work_atio(&ccb->atio); + break; + case XPT_IMMEDIATE_NOTIFY: + retval = work_inot(&ccb->cin1); + break; + default: + warnx("Unhandled ccb type %#x on workq", + ccb_h->func_code); + abort(); + /* NOTREACHED */ + } + + /* Assume work function handled the exception */ + if ((ccb_h->status & CAM_DEV_QFRZN) != 0) { + if (debug) { + warnx("Queue frozen receiving CCB, " + "releasing"); + } + rel_simq(); + } + + /* No more work needed for this command. */ + if (retval == 0) { + TAILQ_REMOVE(&work_queue, ccb_h, + periph_links.tqe); + } + } + + /* + * Poll for new events (i.e. completions) while we + * are processing CCBs on the work_queue. Once it's + * empty, use an infinite wait. + */ + if (!TAILQ_EMPTY(&work_queue)) + tptr = &ts; + else + tptr = NULL; + } +} + +/* CCBs are ready from the kernel */ +static void +handle_read() +{ + union ccb *ccb_array[MAX_INITIATORS], *ccb; + int ccb_count, i, oo; + + ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array)); + if (ccb_count <= 0) { + warn("read ccb ptrs"); + return; + } + ccb_count /= sizeof(union ccb *); + if (ccb_count < 1) { + warnx("truncated read ccb ptr?"); + return; + } + + for (i = 0; i < ccb_count; i++) { + ccb = ccb_array[i]; + TAILQ_REMOVE(&pending_queue, &ccb->ccb_h, periph_links.tqe); + + switch (ccb->ccb_h.func_code) { + case XPT_ACCEPT_TARGET_IO: + { + struct ccb_accept_tio *atio; + struct atio_descr *a_descr; + + /* Initialize ATIO descr for this transaction */ + atio = &ccb->atio; + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + bzero(a_descr, sizeof(*a_descr)); + TAILQ_INIT(&a_descr->cmplt_io); + a_descr->flags = atio->ccb_h.flags & + (CAM_DIS_DISCONNECT | CAM_TAG_ACTION_VALID); + /* XXX add a_descr->priority */ + if ((atio->ccb_h.flags & CAM_CDB_POINTER) == 0) + a_descr->cdb = atio->cdb_io.cdb_bytes; + else + a_descr->cdb = atio->cdb_io.cdb_ptr; + + /* ATIOs are processed in FIFO order */ + TAILQ_INSERT_TAIL(&work_queue, &ccb->ccb_h, + periph_links.tqe); + break; + } + case XPT_CONT_TARGET_IO: + { + struct ccb_scsiio *ctio; + struct ctio_descr *c_descr; + + ctio = &ccb->ctio; + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + c_descr->event = CTIO_DONE; + /* Queue on the appropriate ATIO */ + queue_io(ctio); + /* Process any queued completions. */ + oo += run_queue(c_descr->atio); + break; + } + case XPT_IMMEDIATE_NOTIFY: + /* INOTs are handled with priority */ + TAILQ_INSERT_HEAD(&work_queue, &ccb->ccb_h, + periph_links.tqe); + break; + default: + warnx("Unhandled ccb type %#x in handle_read", + ccb->ccb_h.func_code); + break; + } + } +} + +/* Process an ATIO CCB from the kernel */ +int +work_atio(struct ccb_accept_tio *atio) +{ + struct ccb_scsiio *ctio; + struct atio_descr *a_descr; + struct ctio_descr *c_descr; + cam_status status; + int ret; + + if (debug) + warnx("Working on ATIO %p", atio); + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + + /* Get a CTIO and initialize it according to our known parameters */ + ctio = get_ctio(); + if (ctio == NULL) { + return (1); + } + ret = 0; + ctio->ccb_h.flags = a_descr->flags; + ctio->tag_id = atio->tag_id; + ctio->init_id = atio->init_id; + /* XXX priority needs to be added to a_descr */ + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + c_descr->atio = atio; + if ((a_descr->flags & CAM_DIR_IN) != 0) + c_descr->offset = a_descr->base_off + a_descr->targ_req; + else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) + c_descr->offset = a_descr->base_off + a_descr->init_req; + else + c_descr->offset = a_descr->base_off; + + /* + * Return a check condition if there was an error while + * receiving this ATIO. + */ + if (atio->sense_len != 0) { + struct scsi_sense_data_fixed *sense; + + if (debug) { + warnx("ATIO with %u bytes sense received", + atio->sense_len); + } + sense = (struct scsi_sense_data_fixed *)&atio->sense_data; + tcmd_sense(ctio->init_id, ctio, sense->flags, + sense->add_sense_code, sense->add_sense_code_qual); + send_ccb((union ccb *)ctio, /*priority*/1); + return (0); + } + + status = atio->ccb_h.status & CAM_STATUS_MASK; + switch (status) { + case CAM_CDB_RECVD: + ret = tcmd_handle(atio, ctio, ATIO_WORK); + break; + case CAM_REQ_ABORTED: + warn("ATIO %p aborted", a_descr); + /* Requeue on HBA */ + TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe); + send_ccb((union ccb *)atio, /*priority*/1); + ret = 1; + break; + default: + warnx("ATIO completed with unhandled status %#x", status); + abort(); + /* NOTREACHED */ + break; + } + + return (ret); +} + +static void +queue_io(struct ccb_scsiio *ctio) +{ + struct ccb_hdr *ccb_h; + struct io_queue *ioq; + struct ctio_descr *c_descr; + + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + if (c_descr->atio == NULL) { + errx(1, "CTIO %p has NULL ATIO", ctio); + } + ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io; + + if (TAILQ_EMPTY(ioq)) { + TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); + return; + } + + TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) { + struct ctio_descr *curr_descr = + (struct ctio_descr *)ccb_h->targ_descr; + if (curr_descr->offset <= c_descr->offset) { + break; + } + } + + if (ccb_h) { + TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe); + } else { + TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe); + } +} + +/* + * Go through all completed AIO/CTIOs for a given ATIO and advance data + * counts, start continuation IO, etc. + */ +static int +run_queue(struct ccb_accept_tio *atio) +{ + struct atio_descr *a_descr; + struct ccb_hdr *ccb_h; + int sent_status, event; + + if (atio == NULL) + return (0); + + a_descr = (struct atio_descr *)atio->ccb_h.targ_descr; + + while ((ccb_h = TAILQ_FIRST(&a_descr->cmplt_io)) != NULL) { + struct ccb_scsiio *ctio; + struct ctio_descr *c_descr; + + ctio = (struct ccb_scsiio *)ccb_h; + c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr; + + if (ctio->ccb_h.status == CAM_REQ_ABORTED) { + TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, + periph_links.tqe); + free_ccb((union ccb *)ctio); + send_ccb((union ccb *)atio, /*priority*/1); + continue; + } + + /* If completed item is in range, call handler */ + if ((c_descr->event == AIO_DONE && + c_descr->offset == a_descr->base_off + a_descr->targ_ack) + || (c_descr->event == CTIO_DONE && + c_descr->offset == a_descr->base_off + a_descr->init_ack)) { + sent_status = (ccb_h->flags & CAM_SEND_STATUS) != 0; + event = c_descr->event; + + TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h, + periph_links.tqe); + tcmd_handle(atio, ctio, c_descr->event); + + /* If entire transfer complete, send back ATIO */ + if (sent_status != 0 && event == CTIO_DONE) + send_ccb((union ccb *)atio, /*priority*/1); + } else { + /* Gap in offsets so wait until later callback */ + if (/* debug */ 1) + warnx("IO %p:%p out of order %s", ccb_h, + a_descr, c_descr->event == AIO_DONE? + "aio" : "ctio"); + return (1); + } + } + return (0); +} + +static int +work_inot(struct ccb_immediate_notify *inot) +{ + cam_status status; + + if (debug) + warnx("Working on INOT %p", inot); + + status = inot->ccb_h.status; + status &= CAM_STATUS_MASK; + + switch (status) { + case CAM_SCSI_BUS_RESET: + tcmd_ua(CAM_TARGET_WILDCARD, UA_BUS_RESET); + abort_all_pending(); + break; + case CAM_BDR_SENT: + tcmd_ua(CAM_TARGET_WILDCARD, UA_BDR); + abort_all_pending(); + break; + case CAM_MESSAGE_RECV: + switch (inot->arg) { + case MSG_TASK_COMPLETE: + case MSG_INITIATOR_DET_ERR: + case MSG_ABORT_TASK_SET: + case MSG_MESSAGE_REJECT: + case MSG_NOOP: + case MSG_PARITY_ERROR: + case MSG_TARGET_RESET: + case MSG_ABORT_TASK: + case MSG_CLEAR_TASK_SET: + default: + warnx("INOT message %#x", inot->arg); + break; + } + break; + case CAM_REQ_ABORTED: + warnx("INOT %p aborted", inot); + break; + default: + warnx("Unhandled INOT status %#x", status); + break; + } + + /* Requeue on SIM */ + TAILQ_REMOVE(&work_queue, &inot->ccb_h, periph_links.tqe); + send_ccb((union ccb *)inot, /*priority*/1); + + return (1); +} + +void +send_ccb(union ccb *ccb, int priority) +{ + if (debug) + warnx("sending ccb (%#x)", ccb->ccb_h.func_code); + ccb->ccb_h.pinfo.priority = priority; + if (XPT_FC_IS_QUEUED(ccb)) { + TAILQ_INSERT_TAIL(&pending_queue, &ccb->ccb_h, + periph_links.tqe); + } + if (write(targ_fd, &ccb, sizeof(ccb)) != sizeof(ccb)) { + warn("write ccb"); + ccb->ccb_h.status = CAM_PROVIDE_FAIL; + } +} + +/* Return a CTIO/descr/buf combo from the freelist or malloc one */ +static struct ccb_scsiio * +get_ctio() +{ + struct ccb_scsiio *ctio; + struct ctio_descr *c_descr; + struct sigevent *se; + + if (num_ctios == MAX_CTIOS) { + warnx("at CTIO max"); + return (NULL); + } + + ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio)); + if (ctio == NULL) { + warn("malloc CTIO"); + return (NULL); + } + c_descr = (struct ctio_descr *)malloc(sizeof(*c_descr)); + if (c_descr == NULL) { + free(ctio); + warn("malloc ctio_descr"); + return (NULL); + } + c_descr->buf = malloc(buf_size); + if (c_descr->buf == NULL) { + free(c_descr); + free(ctio); + warn("malloc backing store"); + return (NULL); + } + num_ctios++; + + /* Initialize CTIO, CTIO descr, and AIO */ + ctio->ccb_h.func_code = XPT_CONT_TARGET_IO; + ctio->ccb_h.retry_count = 2; + ctio->ccb_h.timeout = CAM_TIME_INFINITY; + ctio->data_ptr = c_descr->buf; + ctio->ccb_h.targ_descr = c_descr; + c_descr->aiocb.aio_buf = c_descr->buf; + c_descr->aiocb.aio_fildes = file_fd; + se = &c_descr->aiocb.aio_sigevent; + se->sigev_notify = SIGEV_KEVENT; + se->sigev_notify_kqueue = kq_fd; + se->sigev_value.sival_ptr = ctio; + + return (ctio); +} + +void +free_ccb(union ccb *ccb) +{ + switch (ccb->ccb_h.func_code) { + case XPT_CONT_TARGET_IO: + { + struct ctio_descr *c_descr; + + c_descr = (struct ctio_descr *)ccb->ccb_h.targ_descr; + free(c_descr->buf); + num_ctios--; + /* FALLTHROUGH */ + } + case XPT_ACCEPT_TARGET_IO: + free(ccb->ccb_h.targ_descr); + /* FALLTHROUGH */ + case XPT_IMMEDIATE_NOTIFY: + default: + free(ccb); + break; + } +} + +static cam_status +get_sim_flags(u_int16_t *flags) +{ + struct ccb_pathinq cpi; + cam_status status; + + /* Find SIM capabilities */ + bzero(&cpi, sizeof(cpi)); + cpi.ccb_h.func_code = XPT_PATH_INQ; + send_ccb((union ccb *)&cpi, /*priority*/1); + status = cpi.ccb_h.status & CAM_STATUS_MASK; + if (status != CAM_REQ_CMP) { + fprintf(stderr, "CPI failed, status %#x\n", status); + return (status); + } + + /* Can only enable on controllers that support target mode */ + if ((cpi.target_sprt & PIT_PROCESSOR) == 0) { + fprintf(stderr, "HBA does not support target mode\n"); + status = CAM_PATH_INVALID; + return (status); + } + + *flags = cpi.hba_inquiry; + return (status); +} + +static void +rel_simq() +{ + struct ccb_relsim crs; + + bzero(&crs, sizeof(crs)); + crs.ccb_h.func_code = XPT_REL_SIMQ; + crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY; + crs.openings = 0; + crs.release_timeout = 0; + crs.qfrozen_cnt = 0; + send_ccb((union ccb *)&crs, /*priority*/0); +} + +/* Cancel all pending CCBs. */ +static void +abort_all_pending() +{ + struct ccb_abort cab; + struct ccb_hdr *ccb_h; + + if (debug) + warnx("abort_all_pending"); + + bzero(&cab, sizeof(cab)); + cab.ccb_h.func_code = XPT_ABORT; + TAILQ_FOREACH(ccb_h, &pending_queue, periph_links.tqe) { + if (debug) + warnx("Aborting pending CCB %p\n", ccb_h); + cab.abort_ccb = (union ccb *)ccb_h; + send_ccb((union ccb *)&cab, /*priority*/1); + if (cab.ccb_h.status != CAM_REQ_CMP) { + warnx("Unable to abort CCB, status %#x\n", + cab.ccb_h.status); + } + } +} + +static void +usage() +{ + fprintf(stderr, + "Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n" + "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n" + "\t\tbus:target:lun filename\n"); + exit(1); +} diff --git a/share/examples/scsi_target/scsi_target.h b/share/examples/scsi_target/scsi_target.h new file mode 100644 index 000000000000..a873c050b7c6 --- /dev/null +++ b/share/examples/scsi_target/scsi_target.h @@ -0,0 +1,129 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * SCSI Target Emulator + * + * Copyright (c) 2002 Nate Lawson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SCSI_TARGET_H +#define _SCSI_TARGET_H + +/* + * Maximum number of parallel commands to accept, + * 1024 for Fibre Channel (SPI is 16). + */ +#define MAX_INITIATORS 8 +#define SECTOR_SIZE 512 +#define MAX_EVENTS (MAX_INITIATORS + 5) + /* kqueue for AIO, signals */ + +/* Additional SCSI 3 defines for inquiry response */ +#define SID_Addr16 0x0100 + +TAILQ_HEAD(io_queue, ccb_hdr); + +/* Offset into the private CCB area for storing our descriptor */ +#define targ_descr periph_priv.entries[1].ptr + +/* Descriptor attached to each ATIO */ +struct atio_descr { + off_t base_off; /* Base offset for ATIO */ + uint total_len; /* Total xfer len for this ATIO */ + uint init_req; /* Transfer count requested to/from init */ + uint init_ack; /* Data transferred ok to/from init */ + uint targ_req; /* Transfer count requested to/from target */ + uint targ_ack; /* Data transferred ok to/from target */ + int flags; /* Flags for CTIOs */ + u_int8_t *cdb; /* Pointer to received CDB */ + /* List of completed AIO/CTIOs */ + struct io_queue cmplt_io; +}; + +typedef enum { + ATIO_WORK, + AIO_DONE, + CTIO_DONE +} io_ops; + +/* Descriptor attached to each CTIO */ +struct ctio_descr { + void *buf; /* Backing store */ + off_t offset; /* Position in transfer (for file, */ + /* doesn't start at 0) */ + struct aiocb aiocb; /* AIO descriptor for this CTIO */ + struct ccb_accept_tio *atio; + /* ATIO we are satisfying */ + io_ops event; /* Event that queued this CTIO */ +}; + +typedef enum { + UA_NONE = 0x00, + UA_POWER_ON = 0x01, + UA_BUS_RESET = 0x02, + UA_BDR = 0x04 +} ua_types; + +typedef enum { + CA_NONE = 0x00, + CA_UNIT_ATTN = 0x01, + CA_CMD_SENSE = 0x02 +} ca_types; + +struct initiator_state { + ua_types orig_ua; + ca_types orig_ca; + ua_types pending_ua; + ca_types pending_ca; + struct scsi_sense_data sense_data; +}; + +/* Global functions */ +extern cam_status tcmd_init(u_int16_t req_inq_flags, + u_int16_t sim_inq_flags); +extern int tcmd_handle(struct ccb_accept_tio *atio, + struct ccb_scsiio *ctio, io_ops event); +extern void tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, + u_int8_t flags, + u_int8_t asc, u_int8_t ascq); +extern void tcmd_ua(u_int init_id, ua_types new_ua); +extern int work_atio(struct ccb_accept_tio *atio); +extern void send_ccb(union ccb *ccb, int priority); +extern void free_ccb(union ccb *ccb); +static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); } + +/* Global Data */ +extern int notaio; + +/* + * Compat Defines + */ +#if __FreeBSD_version >= 500000 +#define OFF_FMT "%ju" +#else +#define OFF_FMT "%llu" +#endif + +#endif /* _SCSI_TARGET_H */ diff --git a/share/examples/ses/Makefile b/share/examples/ses/Makefile new file mode 100644 index 000000000000..a7191be1e504 --- /dev/null +++ b/share/examples/ses/Makefile @@ -0,0 +1,39 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ses +UNUSED = getobjmap getnobj getobjstat +SUBDIR = getencstat setencstat setobjstat sesd + +.include <bsd.subdir.mk> diff --git a/share/examples/ses/Makefile.inc b/share/examples/ses/Makefile.inc new file mode 100644 index 000000000000..cce490974e11 --- /dev/null +++ b/share/examples/ses/Makefile.inc @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +BINDIR?= /usr/sbin + +CLEANFILES+= ${MAN} + +.SUFFIXES: .0 .8 +.0.8: + cat ${.IMPSRC} > ${.TARGET} diff --git a/share/examples/ses/getencstat/Makefile b/share/examples/ses/getencstat/Makefile new file mode 100644 index 000000000000..d406403ddb57 --- /dev/null +++ b/share/examples/ses/getencstat/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +.PATH: ${.CURDIR}/../srcs + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ses/${PROG} +PROG= getencstat +SRCS= getencstat.c eltsub.c +MAN= getencstat.8 + +.include <bsd.prog.mk> diff --git a/share/examples/ses/getencstat/getencstat.0 b/share/examples/ses/getencstat/getencstat.0 new file mode 100644 index 000000000000..71882d5e7d24 --- /dev/null +++ b/share/examples/ses/getencstat/getencstat.0 @@ -0,0 +1,81 @@ +.\" Copyright (c) 2000 Matthew Jacob +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions, and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" Alternatively, this software may be distributed under the terms of the +.\" the GNU Public License ("GPL"). +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Matthew Jacob +.\" Feral Software +.\" mjacob@feral.com +.\" +.Dd February 21, 2000 +.Dt GETENCSTAT 8 +.Os +.Sh NAME +.Nm getencstat +.Nd get SCSI Environmental Services Device enclosure status +.Sh SYNOPSIS +.Nm +.Op Fl v +.Ar device +.Op Ar device ... +.Sh DESCRIPTION +.Nm +gets summary and detailed SCSI Environmental Services (or SAF-TE) device +enclosure status. +The overall status is printed out. +If the overall status +is considered okay, nothing else is printed out (unless the +.Fl v +option is used). +.Pp +A SCSI Environmental Services device enclosure may be either in the state +of being \fBOK\fR, or in one or more of the states of \fBINFORMATIONAL\fR, +\fBNON-CRITICAL\fR, \fBCRITICAL\fB or \fBUNRECOVERABLE\fR states. +These +overall states reflect a summary of the states of each object within +such a device (such as power supplies or disk drives). +.Pp +With the +.Fl v +option, the status of all objects within the device is printed, whether +\fBOK\fR or not. +Along with the status of each object is the object identifier. +.Pp +The user may then use +.Xr setencstat 8 +to try and clear overall device status, or may use +.Xr setobjstat 8 +to set specific object status. +.Sh FILES +.Bl -tag -width /dev/sesN -compact +.It Pa /dev/ses\fIN\fR +SCSI Environmental Services Devices +.El +.Sh SEE ALSO +.Xr ses 4 , +.Xr sesd 8 , +.Xr setencstat 8 , +.Xr setobjstat 8 +.Sh BUGS diff --git a/share/examples/ses/sesd/Makefile b/share/examples/ses/sesd/Makefile new file mode 100644 index 000000000000..593e95d79288 --- /dev/null +++ b/share/examples/ses/sesd/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +.PATH: ${.CURDIR}/../srcs + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ses/${PROG} +PROG= sesd +SRCS= sesd.c eltsub.c +MAN= sesd.8 + +.include <bsd.prog.mk> diff --git a/share/examples/ses/sesd/sesd.0 b/share/examples/ses/sesd/sesd.0 new file mode 100644 index 000000000000..08fd8ecb53c4 --- /dev/null +++ b/share/examples/ses/sesd/sesd.0 @@ -0,0 +1,86 @@ +.\" Copyright (c) 2000 Matthew Jacob +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions, and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" Alternatively, this software may be distributed under the terms of the +.\" the GNU Public License ("GPL"). +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Matthew Jacob +.\" Feral Software +.\" mjacob@feral.com +.\" +.Dd November 5, 2012 +.Dt SESD 8 +.Os +.Sh NAME +.Nm sesd +.Nd monitor SCSI Environmental Services Devices +.Sh SYNOPSIS +.Nm +.Op Fl c +.Op Fl d +.Op Fl t Ar poll-interval +.Ar device +.Op Ar device ... +.Sh DESCRIPTION +.Nm +monitors SCSI Environmental Services (or SAF-TE) devices for changes +in state and logs such changes to the system error logger +(see +.Xr syslogd 8 ) . +At least one device must be specified. +When no other options are supplied, +.Nm +detached becomes a daemon, by default waking up every 30 seconds to +poll each device for a change in state. +.Pp +The following options may be used: +.Bl -tag -width Ds +.It Fl c +Try to clear enclosure status after read. +.It Fl t Ar poll-interval +Change the interval of polling from the default 30 seconds to the number +of seconds specified. +.It Fl d +Instead of detaching and becoming a daemon, stay attached to the +controlling terminal and log changes there as well as via the system +logger. +.El +.Pp +The user may then use +.Xr getencstat 8 +to get more detailed information about the state of the over enclosure device +or objects within the enclosure device. +.Sh FILES +.Bl -tag -width /dev/sesN -compact +.It Pa /dev/ses\fIN\fR +SCSI Environmental Services Devices +.El +.Sh SEE ALSO +.Xr ses 4 , +.Xr getencstat 8 , +.Xr setencstat 8 , +.Xr setobjstat 8 , +.Xr syslogd 8 +.Sh BUGS +This is something of a toy, but it is better than nothing. diff --git a/share/examples/ses/setencstat/Makefile b/share/examples/ses/setencstat/Makefile new file mode 100644 index 000000000000..a108d6b17ad5 --- /dev/null +++ b/share/examples/ses/setencstat/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +.PATH: ${.CURDIR}/../srcs + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ses/${PROG} +PROG= setencstat +SRCS= setencstat.c eltsub.c +MAN= setencstat.8 + +.include <bsd.prog.mk> diff --git a/share/examples/ses/setencstat/setencstat.0 b/share/examples/ses/setencstat/setencstat.0 new file mode 100644 index 000000000000..1b40b35d6dd0 --- /dev/null +++ b/share/examples/ses/setencstat/setencstat.0 @@ -0,0 +1,71 @@ +.\" Copyright (c) 2000 Matthew Jacob +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions, and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" Alternatively, this software may be distributed under the terms of the +.\" the GNU Public License ("GPL"). +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Matthew Jacob +.\" Feral Software +.\" mjacob@feral.com +.\" +.Dd February 21, 2000 +.Dt SETENCSTAT 8 +.Os +.Sh NAME +.Nm setencstat +.Nd set SCSI Environmental Services Device enclosure status +.Sh SYNOPSIS +.Nm +.Ar device enclosure_status +.Sh DESCRIPTION +.Nm +sets summary status for a SCSI Environmental Services (or SAF-TE) device. +The enclosure status argument may take on the values: +.Bl -tag -width Ds +.It 0 +Set the status to an \fBOK\fR state. +.It 1 +Set the status to an \fBUNRECOVERABLE\fR state. +.It 2 +Set the status to an \fBCRITICAL\fR state. +.It 4 +Set the status to an \fBNON-CRITICAL\fR state. +.It 8 +Set the status to an \fBINFORMATIONAL\fR state. +.El +.Pp +All the non-zero options may be combined. +.Pp +Note that devices may simply and silently ignore the setting of these values. +.Sh FILES +.Bl -tag -width /dev/sesN -compact +.It Pa /dev/ses\fIN\fR +SCSI Environmental Services Devices +.El +.Sh SEE ALSO +.Xr ses 4 , +.Xr getencstat 8 , +.Xr sesd 8 , +.Xr setobjstat 8 +.Sh BUGS diff --git a/share/examples/ses/setobjstat/Makefile b/share/examples/ses/setobjstat/Makefile new file mode 100644 index 000000000000..e34f23e74486 --- /dev/null +++ b/share/examples/ses/setobjstat/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (c) 2000 by Matthew Jacob +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions, and the following disclaimer, +# without modification, immediately at the beginning of the file. +# 2. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# Alternatively, this software may be distributed under the terms of the +# the GNU Public License ("GPL"). +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# Matthew Jacob +# Feral Software +# mjacob@feral.com +# + +.PATH: ${.CURDIR}/../srcs + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/ses/${PROG} +PROG= setobjstat +SRCS= setobjstat.c eltsub.c +MAN= setobjstat.8 + +.include <bsd.prog.mk> diff --git a/share/examples/ses/setobjstat/setobjstat.0 b/share/examples/ses/setobjstat/setobjstat.0 new file mode 100644 index 000000000000..74db543e2a7d --- /dev/null +++ b/share/examples/ses/setobjstat/setobjstat.0 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2000 Matthew Jacob +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions, and the following disclaimer, +.\" without modification, immediately at the beginning of the file. +.\" 2. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" Alternatively, this software may be distributed under the terms of the +.\" the GNU Public License ("GPL"). +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR +.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Matthew Jacob +.\" Feral Software +.\" mjacob@feral.com +.\" +.Dd February 21, 2000 +.Dt SETOBJSTAT 8 +.Os +.Sh NAME +.Nm setobjstat +.Nd set SCSI Environmental Services Device object status +.Sh SYNOPSIS +.Nm +.Ar device objectid stat0 stat1 stat2 stat3 +.Sh DESCRIPTION +.Nm +sets the object status for a SCSI Environmental Services (or SAF-TE) device. +The +.Ar objectid +argument may be determined by running +.Xr getencstat 8 . +.Pp +The status fields are partially common (first byte only, which must +have a value of 0x80 contained in it), but otherwise quite device +specific. +A complete discussion of the possible values is impractical +here. +Please refer to the ANSI SCSI specification (available on +the FTP site ftp.t10.org). +.Pp +Note that devices may simply and silently ignore the setting of these values. +.Sh FILES +.Bl -tag -width /dev/sesN -compact +.It Pa /dev/ses\fIN\fR +SCSI Environmental Services Devices +.El +.Sh SEE ALSO +.Xr ses 4 , +.Xr getencstat 8 , +.Xr sesd 8 , +.Xr setencstat 8 +.Sh BUGS diff --git a/share/examples/ses/srcs/chpmon.c b/share/examples/ses/srcs/chpmon.c new file mode 100644 index 000000000000..40574e16cf0f --- /dev/null +++ b/share/examples/ses/srcs/chpmon.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/ioctl.h> +#include "ses.h" + +/* + * Continuously monitor all named SES devices + * and turn all but INFO enclosure status + * values into CRITICAL enclosure status. + */ +#define BADSTAT \ + (SES_ENCSTAT_UNRECOV|SES_ENCSTAT_CRITICAL|SES_ENCSTAT_NONCRITICAL) +int +main(int a, char **v) +{ + int fd, delay, dev; + ses_encstat stat, *carray; + + if (a < 3) { + fprintf(stderr, "usage: %s polling-interval device " + "[ device ... ]\n", *v); + return (1); + } + delay = atoi(v[1]); + carray = malloc(a); + if (carray == NULL) { + perror("malloc"); + return (1); + } + bzero((void *)carray, a); + + for (;;) { + for (dev = 2; dev < a; dev++) { + fd = open(v[dev], O_RDWR); + if (fd < 0) { + perror(v[dev]); + continue; + } + /* + * First clear any enclosure status, in case it is + * a latched status. + */ + stat = 0; + if (ioctl(fd, SESIOC_SETENCSTAT, (caddr_t) &stat) < 0) { + fprintf(stderr, "%s: SESIOC_SETENCSTAT1: %s\n", + v[dev], strerror(errno)); + (void) close(fd); + continue; + } + /* + * Now get the actual current enclosure status. + */ + if (ioctl(fd, SESIOC_GETENCSTAT, (caddr_t) &stat) < 0) { + fprintf(stderr, "%s: SESIOC_GETENCSTAT: %s\n", + v[dev], strerror(errno)); + (void) close(fd); + continue; + } + + if ((stat & BADSTAT) == 0) { + if (carray[dev]) { + fprintf(stdout, "%s: Clearing CRITICAL " + "condition\n", v[dev]); + carray[dev] = 0; + } + (void) close(fd); + continue; + } + carray[dev] = 1; + fprintf(stdout, "%s: Setting CRITICAL from:", v[dev]); + if (stat & SES_ENCSTAT_UNRECOV) + fprintf(stdout, " UNRECOVERABLE"); + + if (stat & SES_ENCSTAT_CRITICAL) + fprintf(stdout, " CRITICAL"); + + if (stat & SES_ENCSTAT_NONCRITICAL) + fprintf(stdout, " NONCRITICAL"); + putchar('\n'); + stat = SES_ENCSTAT_CRITICAL; + if (ioctl(fd, SESIOC_SETENCSTAT, (caddr_t) &stat) < 0) { + fprintf(stderr, "%s: SESIOC_SETENCSTAT 2: %s\n", + v[dev], strerror(errno)); + } + (void) close(fd); + } + sleep(delay); + } + /* NOTREACHED */ +} diff --git a/share/examples/ses/srcs/eltsub.c b/share/examples/ses/srcs/eltsub.c new file mode 100644 index 000000000000..4173eba4997f --- /dev/null +++ b/share/examples/ses/srcs/eltsub.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_enc.h> + +#include "eltsub.h" + +char * +geteltnm(int type) +{ + static char rbuf[132]; + + switch (type) { + case ELMTYP_UNSPECIFIED: + sprintf(rbuf, "Unspecified"); + break; + case ELMTYP_DEVICE: + sprintf(rbuf, "Device Slot"); + break; + case ELMTYP_POWER: + sprintf(rbuf, "Power Supply"); + break; + case ELMTYP_FAN: + sprintf(rbuf, "Cooling"); + break; + case ELMTYP_THERM: + sprintf(rbuf, "Temperature Sensor"); + break; + case ELMTYP_DOORLOCK: + sprintf(rbuf, "Door Lock"); + break; + case ELMTYP_ALARM: + sprintf(rbuf, "Audible alarm"); + break; + case ELMTYP_ESCC: + sprintf(rbuf, "Enclosure Services Controller Electronics"); + break; + case ELMTYP_SCC: + sprintf(rbuf, "SCC Controller Electronics"); + break; + case ELMTYP_NVRAM: + sprintf(rbuf, "Nonvolatile Cache"); + break; + case ELMTYP_INV_OP_REASON: + sprintf(rbuf, "Invalid Operation Reason"); + break; + case ELMTYP_UPS: + sprintf(rbuf, "Uninterruptible Power Supply"); + break; + case ELMTYP_DISPLAY: + sprintf(rbuf, "Display"); + break; + case ELMTYP_KEYPAD: + sprintf(rbuf, "Key Pad Entry"); + break; + case ELMTYP_ENCLOSURE: + sprintf(rbuf, "Enclosure"); + break; + case ELMTYP_SCSIXVR: + sprintf(rbuf, "SCSI Port/Transceiver"); + break; + case ELMTYP_LANGUAGE: + sprintf(rbuf, "Language"); + break; + case ELMTYP_COMPORT: + sprintf(rbuf, "Communication Port"); + break; + case ELMTYP_VOM: + sprintf(rbuf, "Voltage Sensor"); + break; + case ELMTYP_AMMETER: + sprintf(rbuf, "Current Sensor"); + break; + case ELMTYP_SCSI_TGT: + sprintf(rbuf, "SCSI Target Port"); + break; + case ELMTYP_SCSI_INI: + sprintf(rbuf, "SCSI Initiator Port"); + break; + case ELMTYP_SUBENC: + sprintf(rbuf, "Simple Subenclosure"); + break; + case ELMTYP_ARRAY_DEV: + sprintf(rbuf, "Array Device Slot"); + break; + case ELMTYP_SAS_EXP: + sprintf(rbuf, "SAS Expander"); + break; + case ELMTYP_SAS_CONN: + sprintf(rbuf, "SAS Connector"); + break; + default: + (void) sprintf(rbuf, "<Type 0x%x>", type); + break; + } + return (rbuf); +} + +static char * +scode2ascii(u_char code) +{ + static char rbuf[32]; + switch (code & 0xf) { + case SES_OBJSTAT_UNSUPPORTED: + sprintf(rbuf, "Unsupported"); + break; + case SES_OBJSTAT_OK: + sprintf(rbuf, "OK"); + break; + case SES_OBJSTAT_CRIT: + sprintf(rbuf, "Critical"); + break; + case SES_OBJSTAT_NONCRIT: + sprintf(rbuf, "Noncritical"); + break; + case SES_OBJSTAT_UNRECOV: + sprintf(rbuf, "Unrecoverable"); + break; + case SES_OBJSTAT_NOTINSTALLED: + sprintf(rbuf, "Not Installed"); + break; + case SES_OBJSTAT_UNKNOWN: + sprintf(rbuf, "Unknown"); + break; + case SES_OBJSTAT_NOTAVAIL: + sprintf(rbuf, "Not Available"); + break; + case SES_OBJSTAT_NOACCESS: + sprintf(rbuf, "No Access Allowed"); + break; + default: + sprintf(rbuf, "<Status 0x%x>", code & 0xf); + break; + } + return (rbuf); +} + + +char * +stat2ascii(int eletype __unused, u_char *cstat) +{ + static char ebuf[256], *scode; + + scode = scode2ascii(cstat[0]); + sprintf(ebuf, "status: %s%s%s%s (0x%02x 0x%02x 0x%02x 0x%02x)", + scode, + (cstat[0] & 0x40) ? ", Prd.Fail" : "", + (cstat[0] & 0x20) ? ", Disabled" : "", + (cstat[0] & 0x10) ? ", Swapped" : "", + cstat[0], cstat[1], cstat[2], cstat[3]); + return (ebuf); +} diff --git a/share/examples/ses/srcs/eltsub.h b/share/examples/ses/srcs/eltsub.h new file mode 100644 index 000000000000..0623b4ac1e5c --- /dev/null +++ b/share/examples/ses/srcs/eltsub.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +char * geteltnm(int); +char * stat2ascii(int, u_char *); diff --git a/share/examples/ses/srcs/getencstat.c b/share/examples/ses/srcs/getencstat.c new file mode 100644 index 000000000000..55a7a0e8edc4 --- /dev/null +++ b/share/examples/ses/srcs/getencstat.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_enc.h> + +#include "eltsub.h" + +int +main(int a, char **v) +{ + encioc_string_t stri; + encioc_element_t *objp; + encioc_elm_status_t ob; + encioc_elm_desc_t objd; + encioc_elm_devnames_t objdn; + int fd, nobj, f, i, verbose, quiet, errors; + u_char estat; + char str[32]; + + if (a < 2) { + fprintf(stderr, "usage: %s [ -v ] device [ device ... ]\n", *v); + return (1); + } + errors = quiet = verbose = 0; + if (strcmp(v[1], "-V") == 0) { + verbose = 2; + v++; + } else if (strcmp(v[1], "-v") == 0) { + verbose = 1; + v++; + } else if (strcmp(v[1], "-q") == 0) { + quiet = 1; + verbose = 0; + v++; + } + while (*++v) { + + fd = open(*v, O_RDONLY); + if (fd < 0) { + perror(*v); + continue; + } + if (verbose > 1) { + stri.bufsiz = sizeof(str); + stri.buf = &str[0]; + if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0) + printf("%s: Enclosure Name: %s\n", *v, stri.buf); + stri.bufsiz = sizeof(str); + stri.buf = &str[0]; + if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0) + printf("%s: Enclosure ID: %s\n", *v, stri.buf); + } + if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) { + perror("ENCIOC_GETNELM"); + (void) close(fd); + continue; + } + if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) { + perror("ENCIOC_GETENCSTAT"); + (void) close(fd); + continue; + } + if ((verbose == 0 || quiet == 1) && estat == 0) { + if (quiet == 0) + fprintf(stdout, "%s: Enclosure OK\n", *v); + (void) close(fd); + continue; + } + fprintf(stdout, "%s: Enclosure Status ", *v); + if (estat == 0) { + fprintf(stdout, "<OK"); + } else { + errors++; + f = '<'; + if (estat & SES_ENCSTAT_INFO) { + fprintf(stdout, "%cINFO", f); + f = ','; + } + if (estat & SES_ENCSTAT_NONCRITICAL) { + fprintf(stdout, "%cNONCRITICAL", f); + f = ','; + } + if (estat & SES_ENCSTAT_CRITICAL) { + fprintf(stdout, "%cCRITICAL", f); + f = ','; + } + if (estat & SES_ENCSTAT_UNRECOV) { + fprintf(stdout, "%cUNRECOV", f); + f = ','; + } + } + fprintf(stdout, ">\n"); + objp = calloc(nobj, sizeof (encioc_element_t)); + if (objp == NULL) { + perror("calloc"); + (void) close(fd); + continue; + } + if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) { + perror("ENCIOC_GETELMMAP"); + (void) close(fd); + continue; + } + for (i = 0; i < nobj; i++) { + ob.elm_idx = objp[i].elm_idx; + if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &ob) < 0) { + perror("ENCIOC_GETELMSTAT"); + (void) close(fd); + break; + } + bzero(&objd, sizeof(objd)); + objd.elm_idx = objp[i].elm_idx; + objd.elm_desc_len = UINT16_MAX; + objd.elm_desc_str = calloc(UINT16_MAX, sizeof(char)); + if (objd.elm_desc_str == NULL) { + perror("calloc"); + (void) close(fd); + continue; + } + if (ioctl(fd, ENCIOC_GETELMDESC, (caddr_t)&objd) < 0) { + perror("ENCIOC_GETELMDESC"); + (void) close(fd); + break; + } + bzero(&objdn, sizeof(objdn)); + objdn.elm_idx = objp[i].elm_idx; + objdn.elm_names_size = 128; + objdn.elm_devnames = calloc(128, sizeof(char)); + if (objdn.elm_devnames == NULL) { + perror("calloc"); + (void) close(fd); + break; + } + /* + * This ioctl isn't critical and has a good chance + * of returning -1. + */ + (void)ioctl(fd, ENCIOC_GETELMDEVNAMES, (caddr_t)&objdn); + fprintf(stdout, "Element 0x%x: %s", ob.elm_idx, + geteltnm(objp[i].elm_type)); + fprintf(stdout, ", %s", + stat2ascii(objp[i].elm_type, ob.cstat)); + if (objd.elm_desc_len > 0) + fprintf(stdout, ", descriptor: '%s'", + objd.elm_desc_str); + if (objdn.elm_names_len > 0) + fprintf(stdout, ", dev: '%s'", + objdn.elm_devnames); + fprintf(stdout, "\n"); + free(objdn.elm_devnames); + } + free(objp); + (void) close(fd); + } + return (errors); +} diff --git a/share/examples/ses/srcs/getnobj.c b/share/examples/ses/srcs/getnobj.c new file mode 100644 index 000000000000..6ad1bc892717 --- /dev/null +++ b/share/examples/ses/srcs/getnobj.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_ses.h> + +int +main(int argc, char **argv) +{ + unsigned int nobj; + int fd; + + while (*++argv != NULL) { + char *name = *argv; + fd = open(name, O_RDONLY); + if (fd < 0) { + perror(name); + continue; + } + if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t) &nobj) < 0) { + perror("SESIOC_GETNOBJ"); + } else { + fprintf(stdout, "%s: %d objects\n", name, nobj); + } + close (fd); + } + return (0); +} diff --git a/share/examples/ses/srcs/getobjmap.c b/share/examples/ses/srcs/getobjmap.c new file mode 100644 index 000000000000..a52484185d0e --- /dev/null +++ b/share/examples/ses/srcs/getobjmap.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_ses.h> + +#include "eltsub.h" + +int +main(int a, char **v) +{ + ses_object *objp; + int nobj, fd, i; + + while (*++v) { + fd = open(*v, O_RDONLY); + if (fd < 0) { + perror(*v); + continue; + } + if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t) &nobj) < 0) { + perror("SESIOC_GETNOBJ"); + (void) close(fd); + continue; + } + fprintf(stdout, "%s: %d objects\n", *v, nobj); + if (nobj == 0) { + (void) close(fd); + continue; + } + objp = calloc(nobj, sizeof (ses_object)); + if (objp == NULL) { + perror("calloc"); + (void) close(fd); + continue; + } + if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t) objp) < 0) { + perror("SESIOC_GETOBJMAP"); + (void) close(fd); + continue; + } + for (i = 0; i < nobj; i++) { + printf(" Object %d: ID 0x%x Type '%s'\n", i, + objp[i].obj_id, geteltnm((int)objp[i].object_type)); + } + free(objp); + (void) close(fd); + } + return (0); +} diff --git a/share/examples/ses/srcs/getobjstat.c b/share/examples/ses/srcs/getobjstat.c new file mode 100644 index 000000000000..83a5e6462961 --- /dev/null +++ b/share/examples/ses/srcs/getobjstat.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_ses.h> + +int +main(int a, char **v) +{ + int fd; + int i; + ses_objstat obj; + long cvt; + char *x; + + if (a != 3) { +usage: + fprintf(stderr, "usage: %s device objectid\n", *v); + return (1); + } + fd = open(v[1], O_RDONLY); + if (fd < 0) { + perror(v[1]); + return (1); + } + x = v[2]; + cvt = strtol(v[2], &x, 0); + if (x == v[2]) { + goto usage; + } + obj.obj_id = cvt; + if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t) &obj) < 0) { + perror("SESIOC_GETOBJSTAT"); + return (1); + } + fprintf(stdout, "Object 0x%x: 0x%x 0x%x 0x%x 0x%x\n", obj.obj_id, + obj.cstat[0], obj.cstat[1], obj.cstat[2], obj.cstat[3]); + (void) close(fd); + return (0); +} diff --git a/share/examples/ses/srcs/inienc.c b/share/examples/ses/srcs/inienc.c new file mode 100644 index 000000000000..f72e71552f7b --- /dev/null +++ b/share/examples/ses/srcs/inienc.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_ses.h> + +int +main(int a, char **v) +{ + int fd; + + while (*++v) { + fd = open(*v, O_RDWR); + if (fd < 0) { + perror(*v); + continue; + } + if (ioctl(fd, SESIOC_INIT, NULL) < 0) { + perror("SESIOC_GETNOBJ"); + } + (void) close(fd); + } + return (0); +} diff --git a/share/examples/ses/srcs/sesd.c b/share/examples/ses/srcs/sesd.c new file mode 100644 index 000000000000..9a6cb8cfe34a --- /dev/null +++ b/share/examples/ses/srcs/sesd.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_enc.h> + +#define ALLSTAT (SES_ENCSTAT_UNRECOV | SES_ENCSTAT_CRITICAL | \ + SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) + +/* + * Monitor named SES devices and note (via syslog) any changes in status. + */ + +int +main(int a, char **v) +{ + static const char *usage = + "usage: %s [ -c ] [ -d ] [ -t pollinterval ] device [ device ]\n"; + int fd, polltime, dev, nodaemon, clear, c; + encioc_enc_status_t stat, nstat, *carray; + + if (a < 2) { + fprintf(stderr, usage, *v); + return (1); + } + + nodaemon = 0; + polltime = 30; + clear = 0; + while ((c = getopt(a, v, "cdt:")) != -1) { + switch (c) { + case 'c': + clear = 1; + break; + case 'd': + nodaemon = 1; + break; + case 't': + polltime = atoi(optarg); + break; + default: + fprintf(stderr, usage, *v); + return (1); + } + } + + carray = malloc(a); + if (carray == NULL) { + perror("malloc"); + return (1); + } + for (dev = optind; dev < a; dev++) + carray[dev] = (encioc_enc_status_t) -1; + + /* + * Check to make sure we can open all devices + */ + for (dev = optind; dev < a; dev++) { + fd = open(v[dev], O_RDWR); + if (fd < 0) { + perror(v[dev]); + return (1); + } + if (ioctl(fd, ENCIOC_INIT, NULL) < 0) { + fprintf(stderr, "%s: ENCIOC_INIT fails- %s\n", + v[dev], strerror(errno)); + return (1); + } + (void) close(fd); + } + if (nodaemon == 0) { + if (daemon(0, 0) < 0) { + perror("daemon"); + return (1); + } + openlog("sesd", LOG_CONS, LOG_USER); + } else { + openlog("sesd", LOG_CONS|LOG_PERROR, LOG_USER); + } + + for (;;) { + for (dev = optind; dev < a; dev++) { + fd = open(v[dev], O_RDWR); + if (fd < 0) { + syslog(LOG_ERR, "%s: %m", v[dev]); + continue; + } + + /* + * Get the actual current enclosure status. + */ + if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &stat) < 0) { + syslog(LOG_ERR, + "%s: ENCIOC_GETENCSTAT- %m", v[dev]); + (void) close(fd); + continue; + } + if (stat != 0 && clear) { + nstat = 0; + if (ioctl(fd, ENCIOC_SETENCSTAT, + (caddr_t) &nstat) < 0) { + syslog(LOG_ERR, + "%s: ENCIOC_SETENCSTAT- %m", v[dev]); + } + } + (void) close(fd); + + if (stat == carray[dev]) + continue; + + carray[dev] = stat; + if ((stat & ALLSTAT) == 0) { + syslog(LOG_NOTICE, + "%s: Enclosure Status OK", v[dev]); + } + if (stat & SES_ENCSTAT_INFO) { + syslog(LOG_NOTICE, + "%s: Enclosure Has Information", v[dev]); + } + if (stat & SES_ENCSTAT_NONCRITICAL) { + syslog(LOG_WARNING, + "%s: Enclosure Non-Critical", v[dev]); + } + if (stat & SES_ENCSTAT_CRITICAL) { + syslog(LOG_CRIT, + "%s: Enclosure Critical", v[dev]); + } + if (stat & SES_ENCSTAT_UNRECOV) { + syslog(LOG_ALERT, + "%s: Enclosure Unrecoverable", v[dev]); + } + } + sleep(polltime); + } + /* NOTREACHED */ +} diff --git a/share/examples/ses/srcs/setencstat.c b/share/examples/ses/srcs/setencstat.c new file mode 100644 index 000000000000..dbfbaf27aacb --- /dev/null +++ b/share/examples/ses/srcs/setencstat.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_enc.h> + +int +main(int a, char **v) +{ + int fd; + long val; + encioc_enc_status_t stat; + + if (a != 3) { + fprintf(stderr, "usage: %s device enclosure_status\n", *v); + return (1); + } + fd = open(v[1], O_RDWR); + if (fd < 0) { + perror(v[1]); + return (1); + } + + val = strtol(v[2], NULL, 0); + stat = (encioc_enc_status_t)val; + if (ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &stat) < 0) { + perror("ENCIOC_SETENCSTAT"); + } + (void) close(fd); + return (0); +} diff --git a/share/examples/ses/srcs/setobjstat.c b/share/examples/ses/srcs/setobjstat.c new file mode 100644 index 000000000000..e5d374e5252a --- /dev/null +++ b/share/examples/ses/srcs/setobjstat.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 by Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Matthew Jacob + * Feral Software + * mjacob@feral.com + */ + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <cam/scsi/scsi_all.h> +#include <cam/scsi/scsi_enc.h> + +int +main(int a, char **v) +{ + int fd; + int i; + encioc_elm_status_t obj; + long cvt; + char *x; + + if (a != 7) { +usage: + fprintf(stderr, + "usage: %s device objectid stat0 stat1 stat2 stat3\n", *v); + return (1); + } + fd = open(v[1], O_RDWR); + if (fd < 0) { + perror(v[1]); + return (1); + } + x = v[2]; + cvt = strtol(v[2], &x, 0); + if (x == v[2]) { + goto usage; + } + obj.elm_idx = cvt; + for (i = 0; i < 4; i++) { + x = v[3 + i]; + cvt = strtol(v[3 + i], &x, 0); + if (x == v[3 + i]) { + goto usage; + } + obj.cstat[i] = cvt; + } + if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &obj) < 0) { + perror("ENCIOC_SETELMSTAT"); + } + (void) close(fd); + return (0); +} diff --git a/share/examples/smbfs/Makefile b/share/examples/smbfs/Makefile new file mode 100644 index 000000000000..e38305148005 --- /dev/null +++ b/share/examples/smbfs/Makefile @@ -0,0 +1,10 @@ + +PACKAGE=utilities +FILESDIR= ${SHAREDIR}/examples/smbfs +FILES= dot.nsmbrc + +.PATH: ${SRCTOP}/contrib/smbfs/examples + +SUBDIR= print + +.include <bsd.prog.mk> diff --git a/share/examples/smbfs/Makefile.depend b/share/examples/smbfs/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/smbfs/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/smbfs/print/Makefile b/share/examples/smbfs/print/Makefile new file mode 100644 index 000000000000..0a0fd500724f --- /dev/null +++ b/share/examples/smbfs/print/Makefile @@ -0,0 +1,8 @@ + +PACKAGE=utilities +FILESDIR= ${SHAREDIR}/examples/smbfs/print +FILES= lj6l ljspool printcap.sample tolj + +.PATH: ${SRCTOP}/contrib/smbfs/examples/print + +.include <bsd.prog.mk> diff --git a/share/examples/smbfs/print/Makefile.depend b/share/examples/smbfs/print/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/smbfs/print/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/sound/README b/share/examples/sound/README new file mode 100644 index 000000000000..0188a26348c8 --- /dev/null +++ b/share/examples/sound/README @@ -0,0 +1,66 @@ +Briefly summarised, a general audio application will: +- open(2) +- ioctl(2) +- read(2) +- write(2) +- close(2) + +In this example, read/write will be called in a loop for a duration of +record/playback. Usually, /dev/dsp is the device you want to open, but it can +be any OSS compatible device, even user space one created with virtual_oss. For +configuring sample rate, bit depth and all other configuring of the device +ioctl is used. As devices can support multiple sample rates and formats, what +specific application should do in case there's an error issuing ioctl, as not +all errors are fatal, is upon the developer to decide. As a general guideline +Official OSS development howto should be used. FreeBSD OSS and virtual_oss are +different to a small degree. + +For more advanced OSS and real-time applications, developers need to handle +buffers more carefully. The size of the buffer in OSS is selected using fragment +size size_selector and the buffer size is 2^size_selector for values between 4 +and 16. The formula on the official site is: + +int frag = (max_fragments << 16) | (size_selector); +ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); + +The max_fragments determines in how many fragments the buffer will be, hence if +the size_selector is 4, the requested size is 2^4 = 16 and for the +max_fragments of 2, the total buffer size will be + +(2 ^ size_selector) * max_fragments + +or in this case 32 bytes. Please note that size of buffer is in bytes not +samples. For example, 24bit sample will be represented with 3 bytes. If you're +porting audio app from Linux, you should be aware that 24 bit samples are +represented with 4 bytes (usually int). + +FreeBSD kernel will round up max_fragments and size of fragment/buffer, so the +last thing any OSS code should do is get info about buffer with audio_buf_info +and SNDCTL_DSP_GETOSPACE. That also means that not all values of max_fragments +are permitted. + +From kernel perspective, there are few points OSS developers should be aware of: +- There is a software facing buffer (bs) and a hardware driver buffer (b) +- The sizes can be seen with cat /dev/sndstat as [b:_/_/_] [bs:_/_/_] (needed: + sysctl hw.snd.verbose=2) +- OSS ioctl only concern software buffer fragments, not hardware + +For USB the block size is according to hw.usb.uaudio.buffer_ms sysctl, meaning +2ms at 48kHz gives 0.002 * 48000 = 96 samples per block, all multiples of this +work well. Block size for virtual_oss, if used, should be set accordingly. + +OSS driver insists on reading / writing a certain number of samples at a time, +one fragment full of samples. It is bound to do so in a fixed time frame, to +avoid under- and overruns in communication with the hardware. + +The idea of a total buffer size that holds max_fragments fragments is to give +some slack and allow application to be about max_fragments - 1 fragments late. +Let's call this the jitter tolerance. The jitter tolerance may be much less if +there is a slight mismatch between the period and the samples per fragment. + +Jitter tolerance gets better if we can make either the period or the samples +per fragment considerably smaller than the other. In our case that means we +divide the total buffer size into smaller fragments, keeping overall latency at +the same level. + +Official OSS development howto: http://manuals.opensound.com/developer/DSP.html diff --git a/share/examples/sound/basic.c b/share/examples/sound/basic.c new file mode 100644 index 000000000000..83ecbe6ea9a7 --- /dev/null +++ b/share/examples/sound/basic.c @@ -0,0 +1,99 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Goran Mekić + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "ossinit.h" + +int +main() +{ + config_t config = { + .device = "/dev/dsp", + .channels = -1, + .format = format, + .frag = -1, + .sample_rate = 48000, + .sample_size = sizeof(sample_t), + .buffer_info.fragments = -1, + .mmap = 0, + }; + + /* Initialize device */ + oss_init(&config); + + /* + * Allocate input and output buffers so that their size match + * frag_size + */ + int ret; + int bytes = config.buffer_info.bytes; + int8_t *ibuf = malloc(bytes); + int8_t *obuf = malloc(bytes); + sample_t *channels = malloc(bytes); + + printf( + "bytes: %d, fragments: %d, fragsize: %d, fragstotal: %d, samples: %d\n", + bytes, + config.buffer_info.fragments, + config.buffer_info.fragsize, + config.buffer_info.fragstotal, + config.sample_count + ); + + /* Minimal engine: read input and copy it to the output */ + for (;;) { + ret = read(config.fd, ibuf, bytes); + if (ret < bytes) { + fprintf( + stderr, + "Requested %d bytes, but read %d!\n", + bytes, + ret + ); + break; + } + oss_split(&config, (sample_t *)ibuf, channels); + /* All processing will happen here */ + oss_merge(&config, channels, (sample_t *)obuf); + ret = write(config.fd, obuf, bytes); + if (ret < bytes) { + fprintf( + stderr, + "Requested %d bytes, but wrote %d!\n", + bytes, + ret + ); + break; + } + } + + /* Cleanup */ + free(channels); + free(obuf); + free(ibuf); + close(config.fd); + return (0); +} diff --git a/share/examples/sound/midi.c b/share/examples/sound/midi.c new file mode 100644 index 000000000000..6d6ac9aa0fcd --- /dev/null +++ b/share/examples/sound/midi.c @@ -0,0 +1,76 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Goran Mekić + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <unistd.h> + +#include "ossmidi.h" + +int +main() +{ + midi_event_t event; + midi_config_t midi_config; + int l = -1; + unsigned char raw; + + midi_config.device = "/dev/umidi1.0"; + oss_midi_init(&midi_config); + + while ((l = read(midi_config.fd, &raw, sizeof(raw))) != -1) { + if (!(raw & 0x80)) { + continue; + } + event.type = raw & CMD_MASK; + event.channel = raw & CHANNEL_MASK; + switch (event.type) { + case NOTE_ON: + case NOTE_OFF: + case CONTROLLER_ON: + if ((l = read(midi_config.fd, &(event.note), sizeof(event.note))) == -1) { + perror("Error reading MIDI note"); + exit(1); + } + if ((l = read(midi_config.fd, &(event.velocity), sizeof(event.velocity))) == -1) { + perror("Error reading MIDI velocity"); + exit(1); + } + break; + } + switch (event.type) { + case NOTE_ON: + case NOTE_OFF: + printf("Channel %d, note %d, velocity %d\n", event.channel, event.note, event.velocity); + break; + case CONTROLLER_ON: + printf("Channel %d, controller %d, value %d\n", event.channel, event.controller, event.value); + break; + default: + printf("Unknown event type %d\n", event.type); + } + } + return 0; +} diff --git a/share/examples/sound/ossinit.h b/share/examples/sound/ossinit.h new file mode 100644 index 000000000000..83920712286d --- /dev/null +++ b/share/examples/sound/ossinit.h @@ -0,0 +1,262 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2021 Goran Mekić + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/soundcard.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +#ifndef SAMPLE_SIZE +#define SAMPLE_SIZE 16 +#endif + +/* Format can be unsigned, in which case replace S with U */ +#if SAMPLE_SIZE == 32 +typedef int32_t sample_t; +int format = AFMT_S32_NE; /* Signed 32bit native endian format */ +#elif SAMPLE_SIZE == 16 +typedef int16_t sample_t; +int format = AFMT_S16_NE; /* Signed 16bit native endian format */ +#elif SAMPLE_SIZE == 8 +typedef int8_t sample_t; +int format = AFMT_S8_NE; /* Signed 8bit native endian format */ +#else +#error Unsupported sample format! +typedef int32_t sample_t; +int format = AFMT_S32_NE; /* Not a real value, just silencing + * compiler errors */ +#endif + + + +/* + * Minimal configuration for OSS + * For real world applications, this structure will probably contain many + * more fields + */ +typedef struct config { + char *device; + int channels; + int fd; + int format; + int frag; + int sample_count; + int sample_rate; + int sample_size; + int chsamples; + int mmap; + oss_audioinfo audio_info; + audio_buf_info buffer_info; +} config_t; + + +/* + * Error state is indicated by value=-1 in which case application exits + * with error + */ +static inline void +check_error(const int value, const char *message) +{ + if (value == -1) { + fprintf(stderr, "OSS error: %s %s\n", message, strerror(errno)); + exit(1); + } +} + + + +/* Calculate frag by giving it minimal size of buffer */ +static inline int +size2frag(int x) +{ + int frag = 0; + + while ((1 << frag) < x) { + ++frag; + } + return frag; +} + + +/* + * Split input buffer into channels. Input buffer is in interleaved format + * which means if we have 2 channels (L and R), this is what the buffer of + * 8 samples would contain: L,R,L,R,L,R,L,R. The result are two channels + * containing: L,L,L,L and R,R,R,R. + */ +void +oss_split(config_t *config, sample_t *input, sample_t *output) +{ + int channel; + int index; + + for (int i = 0; i < config->sample_count; ++i) { + channel = i % config->channels; + index = i / config->channels; + output[channel * index] = input[i]; + } +} + + +/* + * Convert channels into interleaved format and place it in output + * buffer + */ +void +oss_merge(config_t *config, sample_t *input, sample_t *output) +{ + for (int channel = 0; channel < config->channels; ++channel) { + for (int index = 0; index < config->chsamples; ++index) { + output[index * config->channels + channel] = input[channel * index]; + } + } +} + +void +oss_init(config_t *config) +{ + int error; + int tmp; + + /* Open the device for read and write */ + config->fd = open(config->device, O_RDWR); + check_error(config->fd, "open"); + + /* Get device information */ + config->audio_info.dev = -1; + error = ioctl(config->fd, SNDCTL_ENGINEINFO, &(config->audio_info)); + check_error(error, "SNDCTL_ENGINEINFO"); + printf("min_channels: %d\n", config->audio_info.min_channels); + printf("max_channels: %d\n", config->audio_info.max_channels); + printf("latency: %d\n", config->audio_info.latency); + printf("handle: %s\n", config->audio_info.handle); + if (config->audio_info.min_rate > config->sample_rate || config->sample_rate > config->audio_info.max_rate) { + fprintf(stderr, "%s doesn't support chosen ", config->device); + fprintf(stderr, "samplerate of %dHz!\n", config->sample_rate); + exit(1); + } + if (config->channels < 1) { + config->channels = config->audio_info.max_channels; + } + + /* + * If device is going to be used in mmap mode, disable all format + * conversions. Official OSS documentation states error code should not be + * checked. http://manuals.opensound.com/developer/mmap_test.c.html#LOC10 + */ + if (config->mmap) { + tmp = 0; + ioctl(config->fd, SNDCTL_DSP_COOKEDMODE, &tmp); + } + + /* + * Set number of channels. If number of channels is chosen to the value + * near the one wanted, save it in config + */ + tmp = config->channels; + error = ioctl(config->fd, SNDCTL_DSP_CHANNELS, &tmp); + check_error(error, "SNDCTL_DSP_CHANNELS"); + if (tmp != config->channels) { /* or check if tmp is close enough? */ + fprintf(stderr, "%s doesn't support chosen ", config->device); + fprintf(stderr, "channel count of %d", config->channels); + fprintf(stderr, ", set to %d!\n", tmp); + } + config->channels = tmp; + + /* Set format, or bit size: 8, 16, 24 or 32 bit sample */ + tmp = config->format; + error = ioctl(config->fd, SNDCTL_DSP_SETFMT, &tmp); + check_error(error, "SNDCTL_DSP_SETFMT"); + if (tmp != config->format) { + fprintf(stderr, "%s doesn't support chosen sample format!\n", config->device); + exit(1); + } + + /* Most common values for samplerate (in kHz): 44.1, 48, 88.2, 96 */ + tmp = config->sample_rate; + error = ioctl(config->fd, SNDCTL_DSP_SPEED, &tmp); + check_error(error, "SNDCTL_DSP_SPEED"); + + /* Get and check device capabilities */ + error = ioctl(config->fd, SNDCTL_DSP_GETCAPS, &(config->audio_info.caps)); + check_error(error, "SNDCTL_DSP_GETCAPS"); + if (!(config->audio_info.caps & PCM_CAP_DUPLEX)) { + fprintf(stderr, "Device doesn't support full duplex!\n"); + exit(1); + } + if (config->mmap) { + if (!(config->audio_info.caps & PCM_CAP_TRIGGER)) { + fprintf(stderr, "Device doesn't support triggering!\n"); + exit(1); + } + if (!(config->audio_info.caps & PCM_CAP_MMAP)) { + fprintf(stderr, "Device doesn't support mmap mode!\n"); + exit(1); + } + } + + /* + * If desired frag is smaller than minimum, based on number of channels + * and format (size in bits: 8, 16, 24, 32), set that as frag. Buffer size + * is 2^frag, but the real size of the buffer will be read when the + * configuration of the device is successful + */ + int min_frag = size2frag(config->sample_size * config->channels); + + if (config->frag < min_frag) { + config->frag = min_frag; + } + + /* + * Allocate buffer in fragments. Total buffer will be split in number + * of fragments (2 by default) + */ + if (config->buffer_info.fragments < 0) { + config->buffer_info.fragments = 2; + } + tmp = ((config->buffer_info.fragments) << 16) | config->frag; + error = ioctl(config->fd, SNDCTL_DSP_SETFRAGMENT, &tmp); + check_error(error, "SNDCTL_DSP_SETFRAGMENT"); + + /* When all is set and ready to go, get the size of buffer */ + error = ioctl(config->fd, SNDCTL_DSP_GETOSPACE, &(config->buffer_info)); + check_error(error, "SNDCTL_DSP_GETOSPACE"); + if (config->buffer_info.bytes < 1) { + fprintf( + stderr, + "OSS buffer error: buffer size can not be %d\n", + config->buffer_info.bytes + ); + exit(1); + } + config->sample_count = config->buffer_info.bytes / config->sample_size; + config->chsamples = config->sample_count / config->channels; +} diff --git a/share/examples/sound/ossmidi.h b/share/examples/sound/ossmidi.h new file mode 100644 index 000000000000..99a6bacffe73 --- /dev/null +++ b/share/examples/sound/ossmidi.h @@ -0,0 +1,63 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Goran Mekić + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> + +#define CMD_MASK 0xF0 +#define NOTE_ON 0x90 +#define NOTE_OFF 0x80 +#define CHANNEL_MASK 0xF +#define CONTROLLER_ON 0xB0 + +typedef struct midi_event { + unsigned char type; + unsigned char channel; + union { + unsigned char note; + unsigned controller; + }; + union { + unsigned char velocity; + unsigned char value; + }; +} midi_event_t; + +typedef struct midi_config { + char *device; + int fd; +} midi_config_t; + +void +oss_midi_init(midi_config_t *config) +{ + if ((config->fd = open(config->device, O_RDWR)) == -1) { + perror("Error opening MIDI device"); + exit(1); + } +} diff --git a/share/examples/sunrpc/Makefile b/share/examples/sunrpc/Makefile new file mode 100644 index 000000000000..231d2f0262f5 --- /dev/null +++ b/share/examples/sunrpc/Makefile @@ -0,0 +1,25 @@ +# Build all demo services +# +# + +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/sunrpc +MAKE = make +LIB= + +SUBDIR= dir msg sort + +all: ${SUBDIR} + +clean cleanup: + cd dir; $(MAKE) ${MFLAGS} cleanup + cd msg; $(MAKE) ${MFLAGS} cleanup + cd sort; $(MAKE) ${MFLAGS} cleanup + +install: + @echo "No installations done." + +${SUBDIR}: FRC + cd $@; $(MAKE) ${MFLAGS} LIB=$(LIB) + +FRC: diff --git a/share/examples/sunrpc/dir/Makefile b/share/examples/sunrpc/dir/Makefile new file mode 100644 index 000000000000..5d66e639025d --- /dev/null +++ b/share/examples/sunrpc/dir/Makefile @@ -0,0 +1,25 @@ +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/sunrpc/dir +BIN = dir_svc rls +GEN = dir_clnt.c dir_svc.c dir_xdr.c dir.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +$(GEN): dir.x + $(RPCCOM) dir.x + +dir_svc: dir_proc.o dir_svc.o dir_xdr.o + $(CC) -o $@ dir_proc.o dir_svc.o dir_xdr.o $(LIB) + +rls: rls.o dir_clnt.o dir_xdr.o + $(CC) -o $@ rls.o dir_clnt.o dir_xdr.o $(LIB) + +rls.o: rls.c dir.h + +dir_proc.o: dir_proc.c dir.h + +clean cleanup: + rm -f $(GEN) *.o $(BIN) + diff --git a/share/examples/sunrpc/dir/dir.x b/share/examples/sunrpc/dir/dir.x new file mode 100644 index 000000000000..ddd5d0f43c4e --- /dev/null +++ b/share/examples/sunrpc/dir/dir.x @@ -0,0 +1,36 @@ +/* + * dir.x: Remote directory listing protocol + */ +const MAXNAMELEN = 255; /* maximum length of a directory entry */ + +typedef string nametype<MAXNAMELEN>; /* a directory entry */ + +typedef struct namenode *namelist; /* a link in the listing */ + +/* + * A node in the directory listing + */ +struct namenode { + nametype name; /* name of directory entry */ + namelist next; /* next entry */ +}; + +/* + * The result of a READDIR operation. + */ +union readdir_res switch (int errno) { +case 0: + namelist list; /* no error: return directory listing */ +default: + void; /* error occurred: nothing else to return */ +}; + +/* + * The directory program definition + */ +program DIRPROG { + version DIRVERS { + readdir_res + READDIR(nametype) = 1; + } = 1; +} = 76; diff --git a/share/examples/sunrpc/dir/dir_proc.c b/share/examples/sunrpc/dir/dir_proc.c new file mode 100644 index 000000000000..afeda53d5243 --- /dev/null +++ b/share/examples/sunrpc/dir/dir_proc.c @@ -0,0 +1,54 @@ +/* + * dir_proc.c: remote readdir implementation + */ +#include <rpc/rpc.h> +#include <sys/dir.h> +#include "dir.h" + +extern int errno; +extern char *malloc(); +extern char *strcpy(); + +readdir_res * +readdir_1(dirname) + nametype *dirname; +{ + DIR *dirp; + struct direct *d; + namelist nl; + namelist *nlp; + static readdir_res res; /* must be static! */ + + /* + * Open directory + */ + dirp = opendir(*dirname); + if (dirp == NULL) { + res.errno = errno; + return (&res); + } + + /* + * Free previous result + */ + xdr_free(xdr_readdir_res, &res); + + /* + * Collect directory entries + */ + nlp = &res.readdir_res_u.list; + while (d = readdir(dirp)) { + nl = *nlp = (namenode *) malloc(sizeof(namenode)); + nl->name = malloc(strlen(d->d_name)+1); + strcpy(nl->name, d->d_name); + nlp = &nl->next; + } + *nlp = NULL; + + /* + * Return the result + */ + res.errno = 0; + closedir(dirp); + return (&res); +} diff --git a/share/examples/sunrpc/dir/rls.c b/share/examples/sunrpc/dir/rls.c new file mode 100644 index 000000000000..5c39b7139e14 --- /dev/null +++ b/share/examples/sunrpc/dir/rls.c @@ -0,0 +1,80 @@ +/* + * rls.c: Remote directory listing client + */ +#include <stdio.h> +#include <rpc/rpc.h> /* always need this */ +#include "dir.h" /* need this too: will be generated by rpcgen*/ + +extern int errno; + +main(argc, argv) + int argc; + char *argv[]; +{ + CLIENT *cl; + char *server; + char *dir; + readdir_res *result; + namelist nl; + + + if (argc != 3) { + fprintf(stderr, "usage: %s host directory\n", argv[0]); + exit(1); + } + + /* + * Remember what our command line arguments refer to + */ + server = argv[1]; + dir = argv[2]; + + /* + * Create client "handle" used for calling DIRPROG on the + * server designated on the command line. We tell the rpc package + * to use the "tcp" protocol when contacting the server. + */ + cl = clnt_create(server, DIRPROG, DIRVERS, "tcp"); + if (cl == NULL) { + /* + * Couldn't establish connection with server. + * Print error message and die. + */ + clnt_pcreateerror(server); + exit(1); + } + + /* + * Call the remote procedure "readdir" on the server + */ + result = readdir_1(&dir, cl); + if (result == NULL) { + /* + * An error occurred while calling the server. + * Print error message and die. + */ + clnt_perror(cl, server); + exit(1); + } + + /* + * Okay, we successfully called the remote procedure. + */ + if (result->errno != 0) { + /* + * A remote system error occurred. + * Print error message and die. + */ + errno = result->errno; + perror(dir); + exit(1); + } + + /* + * Successfully got a directory listing. + * Print it out. + */ + for (nl = result->readdir_res_u.list; nl != NULL; nl = nl->next) { + printf("%s\n", nl->name); + } +} diff --git a/share/examples/sunrpc/msg/Makefile b/share/examples/sunrpc/msg/Makefile new file mode 100644 index 000000000000..4ccb7f62e3db --- /dev/null +++ b/share/examples/sunrpc/msg/Makefile @@ -0,0 +1,35 @@ +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/sunrpc/msg +BIN = printmsg msg_svc rprintmsg +GEN = msg_clnt.c msg_svc.c msg.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +# +# This is the non-networked version of the program +# +printmsg: printmsg.o + $(CC) -o $@ printmsg.o + +# +# note: no xdr routines are generated here, due this service's +# use of basic data types. +# +$(GEN): msg.x + $(RPCCOM) msg.x + +msg_svc: msg_proc.o msg_svc.o + $(CC) -o $@ msg_proc.o msg_svc.o $(LIB) + +rprintmsg: rprintmsg.o msg_clnt.o + $(CC) -o $@ rprintmsg.o msg_clnt.o $(LIB) + +rprintmsg.o: rprintmsg.c msg.h + +msg_proc.o: msg_proc.c msg.h + +clean cleanup: + rm -f $(GEN) *.o $(BIN) + diff --git a/share/examples/sunrpc/msg/msg.x b/share/examples/sunrpc/msg/msg.x new file mode 100644 index 000000000000..8df021add840 --- /dev/null +++ b/share/examples/sunrpc/msg/msg.x @@ -0,0 +1,8 @@ +/* + * msg.x: Remote message printing protocol + */ +program MESSAGEPROG { + version MESSAGEVERS { + int PRINTMESSAGE(string) = 1; + } = 1; +} = 99; diff --git a/share/examples/sunrpc/msg/msg_proc.c b/share/examples/sunrpc/msg/msg_proc.c new file mode 100644 index 000000000000..bd0797fc15bc --- /dev/null +++ b/share/examples/sunrpc/msg/msg_proc.c @@ -0,0 +1,28 @@ +/* + * msg_proc.c: implementation of the remote procedure "printmessage" + */ +#include <paths.h> +#include <stdio.h> +#include <rpc/rpc.h> /* always need this here */ +#include "msg.h" /* need this too: msg.h will be generated by rpcgen */ + +/* + * Remote version of "printmessage" + */ +int * +printmessage_1(msg) + char **msg; +{ + static int result; /* must be static! */ + FILE *f; + + f = fopen(_PATH_CONSOLE, "w"); + if (f == NULL) { + result = 0; + return (&result); + } + fprintf(f, "%s\n", *msg); + fclose(f); + result = 1; + return (&result); +} diff --git a/share/examples/sunrpc/msg/printmsg.c b/share/examples/sunrpc/msg/printmsg.c new file mode 100644 index 000000000000..6058eb94fb82 --- /dev/null +++ b/share/examples/sunrpc/msg/printmsg.c @@ -0,0 +1,43 @@ +/* + * printmsg.c: print a message on the console + */ +#include <paths.h> +#include <stdio.h> + +main(argc, argv) + int argc; + char *argv[]; +{ + char *message; + + if (argc < 2) { + fprintf(stderr, "usage: %s <message>\n", argv[0]); + exit(1); + } + message = argv[1]; + + if (!printmessage(message)) { + fprintf(stderr, "%s: sorry, couldn't print your message\n", + argv[0]); + exit(1); + } + printf("Message delivered!\n"); +} + +/* + * Print a message to the console. + * Return a boolean indicating whether the message was actually printed. + */ +printmessage(msg) + char *msg; +{ + FILE *f; + + f = fopen(_PATH_CONSOLE, "w"); + if (f == NULL) { + return (0); + } + fprintf(f, "%s\n", msg); + fclose(f); + return(1); +} diff --git a/share/examples/sunrpc/msg/rprintmsg.c b/share/examples/sunrpc/msg/rprintmsg.c new file mode 100644 index 000000000000..25f09cb097dc --- /dev/null +++ b/share/examples/sunrpc/msg/rprintmsg.c @@ -0,0 +1,73 @@ +/* + * rprintmsg.c: remote version of "printmsg.c" + */ +#include <stdio.h> +#include <rpc/rpc.h> /* always need this */ +#include "msg.h" /* need this too: will be generated by rpcgen*/ + +main(argc, argv) + int argc; + char *argv[]; +{ + CLIENT *cl; + int *result; + char *server; + char *message; + + if (argc < 3) { + fprintf(stderr, "usage: %s host message\n", argv[0]); + exit(1); + } + + /* + * Remember what our command line arguments refer to + */ + server = argv[1]; + message = argv[2]; + + /* + * Create client "handle" used for calling MESSAGEPROG on the + * server designated on the command line. We tell the rpc package + * to use the "tcp" protocol when contacting the server. + */ + cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp"); + if (cl == NULL) { + /* + * Couldn't establish connection with server. + * Print error message and die. + */ + clnt_pcreateerror(server); + exit(1); + } + + /* + * Call the remote procedure "printmessage" on the server + */ + result = printmessage_1(&message, cl); + if (result == NULL) { + /* + * An error occurred while calling the server. + * Print error message and die. + */ + clnt_perror(cl, server); + exit(1); + } + + /* + * Okay, we successfully called the remote procedure. + */ + if (*result == 0) { + /* + * Server was unable to print our message. + * Print error message and die. + */ + fprintf(stderr, "%s: sorry, %s couldn't print your message\n", + argv[0], server); + exit(1); + } + + /* + * The message got printed on the server's console + */ + printf("Message delivered to %s!\n", server); +} diff --git a/share/examples/sunrpc/sort/Makefile b/share/examples/sunrpc/sort/Makefile new file mode 100644 index 000000000000..9ea4044b0b67 --- /dev/null +++ b/share/examples/sunrpc/sort/Makefile @@ -0,0 +1,34 @@ +PACKAGE=examples +FILESDIR=${SHAREDIR}/examples/sunrpc/sort +BIN = rsort sort_svc +GEN = sort_clnt.c sort_svc.c sort_xdr.c sort.h +LIB = -lrpclib +RPCCOM = rpcgen + +all: $(BIN) + +rsort: rsort.o sort_clnt.o sort_xdr.o + $(CC) $(LDFLAGS) -o $@ rsort.o sort_clnt.o sort_xdr.o $(LIB) + +rsort.o: rsort.c sort.h + +sort_clnt.c: + $(RPCCOM) -l sort.x >$@ + +sort_svc: sort_proc.o sort_svc.o sort_xdr.o + $(CC) $(LDFLAGS) -o $@ sort_proc.o sort_svc.o sort_xdr.o $(LIB) + +sort_proc.o: sort_proc.c sort.h + +sort_svc.c: + $(RPCCOM) -s udp sort.x >$@ + +sort_xdr.c: + $(RPCCOM) -c sort.x >$@ + +sort.h: + $(RPCCOM) -h sort.x >$@ + +clean cleanup: + rm -f $(GEN) *.o $(BIN) + diff --git a/share/examples/sunrpc/sort/rsort.c b/share/examples/sunrpc/sort/rsort.c new file mode 100644 index 000000000000..1a96d826d096 --- /dev/null +++ b/share/examples/sunrpc/sort/rsort.c @@ -0,0 +1,42 @@ +/* + * rsort.c + * Client side application which sorts argc, argv. + */ +#include <stdio.h> +#include <rpc/rpc.h> +#include "sort.h" + +main(argc, argv) + int argc; + char **argv; +{ + char *machinename; + struct sortstrings args, res; + int i; + + if (argc < 3) { + fprintf(stderr, "usage: %s machinename [s1 ...]\n", argv[0]); + exit(1); + } + machinename = argv[1]; + args.ss.ss_len = argc - 2; /* substract off progname, machinename */ + args.ss.ss_val = &argv[2]; + res.ss.ss_val = (char **)NULL; + + if ((i = callrpc(machinename, SORTPROG, SORTVERS, SORT, + xdr_sortstrings, &args, xdr_sortstrings, &res))) + { + fprintf(stderr, "%s: call to sort service failed. ", argv[0]); + clnt_perrno(i); + fprintf(stderr, "\n"); + exit(1); + } + + for (i = 0; i < res.ss.ss_len; i++) { + printf("%s\n", res.ss.ss_val[i]); + } + + /* should free res here */ + exit(0); +} + diff --git a/share/examples/sunrpc/sort/sort.x b/share/examples/sunrpc/sort/sort.x new file mode 100644 index 000000000000..9db635fa0eb5 --- /dev/null +++ b/share/examples/sunrpc/sort/sort.x @@ -0,0 +1,18 @@ +/* + * The sort procedure receives an array of strings and returns an array + * of strings. This toy service handles a maximum of 64 strings. + */ +const MAXSORTSIZE = 64; +const MAXSTRINGLEN = 64; + +typedef string str<MAXSTRINGLEN>; /* the string itself */ + +struct sortstrings { + str ss<MAXSORTSIZE>; +}; + +program SORTPROG { + version SORTVERS { + sortstrings SORT(sortstrings) = 1; + } = 1; +} = 22855; diff --git a/share/examples/sunrpc/sort/sort_proc.c b/share/examples/sunrpc/sort/sort_proc.c new file mode 100644 index 000000000000..d09df48ca883 --- /dev/null +++ b/share/examples/sunrpc/sort/sort_proc.c @@ -0,0 +1,26 @@ +#include <rpc/rpc.h> +#include "sort.h" + +static int +comparestrings(sp1, sp2) + char **sp1, **sp2; +{ + return (strcmp(*sp1, *sp2)); +} + +struct sortstrings * +sort_1(ssp) + struct sortstrings *ssp; +{ + static struct sortstrings ss_res; + + if (ss_res.ss.ss_val != (str *)NULL) + free(ss_res.ss.ss_val); + + qsort(ssp->ss.ss_val, ssp->ss.ss_len, sizeof (char *), comparestrings); + ss_res.ss.ss_len = ssp->ss.ss_len; + ss_res.ss.ss_val = (str *)malloc(ssp->ss.ss_len * sizeof(str *)); + bcopy(ssp->ss.ss_val, ss_res.ss.ss_val, + ssp->ss.ss_len * sizeof(str *)); + return(&ss_res); +} diff --git a/share/examples/tests/Makefile b/share/examples/tests/Makefile new file mode 100644 index 000000000000..8f257929d60f --- /dev/null +++ b/share/examples/tests/Makefile @@ -0,0 +1,7 @@ + +SUBDIR= tests + +.PATH: ${SRCTOP}/tests +KYUAFILE= yes + +.include <bsd.test.mk> diff --git a/share/examples/tests/Makefile.depend b/share/examples/tests/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/tests/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/tests/README b/share/examples/tests/README new file mode 100644 index 000000000000..ecf3c36a01f1 --- /dev/null +++ b/share/examples/tests/README @@ -0,0 +1,36 @@ + +This directory contains sample test programs along the Makefile and +Kyuafile logic to get them build and installed. + +The goal of these test programs is to illustrate, via simple and +heaviliy-commented code, how to construct test programs using all the +supported interfaces in the system. + +If you use any files in here as templates for your own code, please +remove all comments while doing so and then write your own if necessary. + +The subdirectories here contain: + +* tests/: Regular directory containing the tests code. Note that the + apparently-redundant tests/tests/ path component here is expected for + consistency reasons and required to get the right layout under + /usr/tests/. + +* tests/atf/: Tests that use the ATF libraries, including atf-c, atf-c++ + and atf-sh. See kyua-atf-interface(1) for details. + +* tests/plain/: Tests that do not use any testing framework. See + kyua-plain-interface(1) for details. + +To inspect the available sample test cases from an installed system: + + $ kyua list -k /usr/tests/share/examples/tests/Kyuafile + +To run the full suite of sample test cases: + + $ kyua test -k /usr/tests/share/examples/tests/Kyuafile + +And to debug a specific failing test case, if any: + + $ kyua debug -k /usr/tests/share/examples/tests/Kyuafile \ + atf/cp_test:simple diff --git a/share/examples/tests/tests/Makefile b/share/examples/tests/tests/Makefile new file mode 100644 index 000000000000..ecaa1b5b9037 --- /dev/null +++ b/share/examples/tests/tests/Makefile @@ -0,0 +1,35 @@ + +.include <src.opts.mk> + +# Directory into which the Kyuafile provided by this directory will be +# installed. +# +# This is always a subdirectory of ${TESTSBASE}/. The remainder of the +# path has to match the relative path within the source tree in which +# these files are found modulo the tests/ component at the end. +# +# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR +# would point at ${TESTSBASE}/bin/cp/. +# +# The default path specified by bsd.test.mk is `${TESTSBASE}/${RELDIR:H}`, +# which happens to be the same as `${TESTSBASE}/share/examples/tests`. +#TESTSDIR= ${TESTSBASE}/share/examples/tests + +# List of subdirectories into which we want to recurse during the build +# of the system. We use TESTS_SUBDIRS instead of SUBDIR because we want +# the auto-generated Kyuafile to recurse into these directories. +TESTS_SUBDIRS+= atf +TESTS_SUBDIRS+= plain +TESTS_SUBDIRS+= tap + +.if ${MK_GOOGLETEST} != no +TESTS_SUBDIRS+= googletest +.endif + +# We leave KYUAFILE unset so that bsd.test.mk auto-generates a Kyuafile +# for us based on the contents of the TESTS_SUBDIRS line above. The +# generated file will tell the tests run-time engine to recurse into the +# directories listed above. +#KYUAFILE= auto + +.include <bsd.test.mk> diff --git a/share/examples/tests/tests/Makefile.depend b/share/examples/tests/tests/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/tests/tests/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/tests/tests/atf/Kyuafile b/share/examples/tests/tests/atf/Kyuafile new file mode 100644 index 000000000000..ef2407d0f11c --- /dev/null +++ b/share/examples/tests/tests/atf/Kyuafile @@ -0,0 +1,45 @@ +-- +-- Copyright 2013 Google Inc. +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are +-- met: +-- +-- * Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- * Neither the name of Google Inc. nor the names of its contributors +-- may be used to endorse or promote products derived from this software +-- without specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax(2) + +-- All tests provided by the FreeBSD base system should set the test_suite +-- property to FreeBSD. This creates a namespace in the configuration file +-- in which specific run-time properties can be passed to the tests below. +test_suite('FreeBSD') + +-- Register the various test programs into the test suite defined in this +-- directory. +-- +-- Note that, while Kyua supports overriding the test case metadata +-- properties (e.g. their timeout) along the test program definition, you +-- should not do so for ATF test programs. The ATF test cases themselves +-- encode the right values. +atf_test_program{name='cp_test'} +atf_test_program{name='printf_test'} diff --git a/share/examples/tests/tests/atf/Makefile b/share/examples/tests/tests/atf/Makefile new file mode 100644 index 000000000000..7614767b6e0a --- /dev/null +++ b/share/examples/tests/tests/atf/Makefile @@ -0,0 +1,52 @@ + +# The release package to use for the tests contained within the directory +# +# This applies to components which rely on ^/projects/release-pkg support +# (see UPDATING XXXXXXXXX / svn revision r298107). +PACKAGE= tests + +# Directory into which the Kyuafile provided by this directory will be +# installed. +# +# This is always a subdirectory of ${TESTSBASE}/. The remainder of the +# path has to match the relative path within the source tree in which +# these files are found modulo the tests/ component at the end. +# +# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR +# would point at ${TESTSBASE}/bin/cp/. +TESTSDIR= ${TESTSBASE}/share/examples/tests/atf + +# List of test programs to build. Note that we can build more than one +# test from a single directory, and this is expected. +ATF_TESTS_C= printf_test +ATF_TESTS_SH= cp_test + +# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this +# directory. We do so because the file in this directory exists for +# documentation purposes. +# +# In general, however, you should NOT define KYUAFILE at all to allow +# bsd.test.mk auto-generate one for you based on the ATF_TESTS_* +# definitions from above. +KYUAFILE= yes + +# Install file1 and file2 as files via bsd.progs.mk. Please note the intentional +# ${PACKAGE} namespace of files. +# +# The basic semantics of this are the same as FILES in bsd.progs.mk, e.g. the +# installation of the files can be manipulated via ${PACKAGE}FILESDIR, +# ${PACKAGE}FILESMODE, etc. +# +# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE} +# namespace if release package support isn't needed. +${PACKAGE}FILES+= file1 +CLEANFILES+= file1 + +file1: + @echo "File 1" > ${.TARGET} + +.include <bsd.test.mk> + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/examples/tests/tests/atf/Makefile.depend b/share/examples/tests/tests/atf/Makefile.depend new file mode 100644 index 000000000000..1af0c88e099c --- /dev/null +++ b/share/examples/tests/tests/atf/Makefile.depend @@ -0,0 +1,17 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/atf/libatf-c \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/tests/tests/atf/cp_test.sh b/share/examples/tests/tests/atf/cp_test.sh new file mode 100644 index 000000000000..d06786c9d0ce --- /dev/null +++ b/share/examples/tests/tests/atf/cp_test.sh @@ -0,0 +1,120 @@ +# +# SPDX-License-Identifier: BSD-3-Clause +# +# Copyright 2013 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# +# INTRODUCTION +# +# This sample test program implements various test cases for the cp(1) +# utility in order to demonstrate the usage of the ATF shell API (see +# atf-sh-api(3)). +# + +# +# Auxiliary function to compare two files for equality. +# +verify_copy() { + if ! cmp -s "${1}" "${2}"; then + echo "${1} and ${2} differ, but they should be equal" + diff -u "${1}" "${2}" + atf_fail "Original and copy do not match" + fi +} + +# +# This is the simplest form of a test case definition: a test case +# without a header. +# +# In most cases, this is the definition you will want to use. However, +# make absolutely sure that the test case name is descriptive enough. +# Multi-word test case names are encouraged. Keep in mind that these +# are exposed to the reader in the test reports, and the goal is for +# the combination of the test program plus the name of the test case to +# give a pretty clear idea of what specific condition the test is +# validating. +# +atf_test_case simple +simple_body() { + cp $(atf_get_srcdir)/file1 . + + # The atf_check function is a very powerful function of atf-sh. + # It allows you to define checkers for the exit status, the + # stdout and the stderr of any command you execute. If the + # result of the command does not match the expectations defined + # in the checkers, the test fails and verbosely reports data + # behind the problem. + # + # See atf-check(1) for details. + atf_check -s exit:0 -o empty -e empty cp file1 file2 + + verify_copy file1 file2 + + # Of special note here is that we are NOT deleting the temporary + # files we created in this test. Kyua takes care of this + # cleanup automatically and tests can (and should) rely on this + # behavior. +} + +# +# This is a more complex form of a test case definition: a test case +# with a header and a body. You should always favor the simpler +# definition above unless you have to override specific metadata +# variables. +# +# See atf-test-case(4) and kyua-atf-interface(1) for details on all +# available properties. +# +atf_test_case force +force_head() { + # In this specific case, we define a textual description for + # the test case, which is later exported to the reports for + # documentation purposes. + # + # However, note again that you should favor highly descriptive + # test case names to textual descriptions. + atf_set "descr" "Tests that the -f flag causes cp to forcibly" \ + "override the destination file" +} +force_body() { + cp $(atf_get_srcdir)/file1 . + echo 'File 2' >file2 + chmod 400 file2 + atf_check cp -f file1 file2 + verify_copy file1 file2 +} + +# +# Lastly, we tell ATF which test cases exist in this program. This +# function should not do anything other than this registration. +# +atf_init_test_cases() { + atf_add_test_case simple + atf_add_test_case force +} diff --git a/share/examples/tests/tests/atf/printf_test.c b/share/examples/tests/tests/atf/printf_test.c new file mode 100644 index 000000000000..d837c6b7686f --- /dev/null +++ b/share/examples/tests/tests/atf/printf_test.c @@ -0,0 +1,158 @@ +/* + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2013 Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* + * INTRODUCTION + * + * This sample test program implements various test cases for the printf(3) + * family of functions in order to demonstrate the usage of the ATF C API + * (see atf-c-api(3)). + * + * Note that this test program is called printf_test because it is intended + * to validate various functions of the printf(3) family. For this reason, + * each test is prefixed with the name of the function under test followed + * by a description of the specific condition being validated. You should + * use a similar naming scheme for your own tests. + */ + +#include <atf-c.h> +#include <stdio.h> +#include <string.h> + +/* + * This is the simplest form of a test case definition: a test case + * without a header. + * + * In most cases, this is the definition you will want to use. However, + * make absolutely sure that the test case name is descriptive enough. + * Multi-word test case names are encouraged. Keep in mind that these + * are exposed to the reader in the test reports, and the goal is for + * the combination of the test program plus the name of the test case to + * give a pretty clear idea of what specific condition the test is + * validating. + */ +ATF_TC_WITHOUT_HEAD(snprintf__two_formatters); +ATF_TC_BODY(snprintf__two_formatters, tc) +{ + char buffer[128]; + + /* This first require-style check invokes the function we are + * interested in testing. This will cause the test to fail if + * the condition provided to ATF_REQUIRE is not met. */ + ATF_REQUIRE(snprintf(buffer, sizeof(buffer), "%s, %s!", + "Hello", "tests") > 0); + + /* This second check-style check compares that the result of the + * snprintf call we performed above is correct. We use a check + * instead of a require. */ + ATF_CHECK_STREQ("Hello, tests!", buffer); +} + +/* + * This is a more complex form of a test case definition: a test case + * with a header and a body. You should always favor the simpler + * definition above unless you have to override specific metadata + * variables. + * + * See atf-test-case(4) and kyua-atf-interface(1) for details on all + * available properties. + */ +ATF_TC(snprintf__overflow); +ATF_TC_HEAD(snprintf__overflow, tc) +{ + /* In this specific case, we define a textual description for + * the test case, which is later exported to the reports for + * documentation purposes. + * + * However, note again that you should favor highly descriptive + * test case names to textual descriptions. */ + atf_tc_set_md_var(tc, "descr", "This test case validates the proper " + "truncation of the output string from snprintf when it does not " + "fit the provided buffer."); +} +ATF_TC_BODY(snprintf__overflow, tc) +{ + char buffer[10]; + + /* This is a similar test to the above, but in this case we do the + * test ourselves and forego the ATF_* macros. Note that we use the + * atf_tc_fail() function instead of exit(2) or similar because we + * want Kyua to have access to the failure message. + * + * In general, prefer using the ATF_* macros wherever possible. Only + * resort to manual tests when the macros are unsuitable (and consider + * filing a feature request to get a new macro if you think your case + * is generic enough). */ + if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16) + atf_tc_fail("snprintf did not return the expected number " + "of characters"); + + ATF_CHECK(strcmp(buffer, "012345678") == 0); +} + +/* + * Another simple test case, but this time with side-effects. This + * particular test case modifies the contents of the current directory + * and does not clean up after itself, which is perfectly fine. + */ +ATF_TC_WITHOUT_HEAD(fprintf__simple_string); +ATF_TC_BODY(fprintf__simple_string, tc) +{ + const char *contents = "This is a message\n"; + + FILE *output = fopen("test.txt", "w"); + ATF_REQUIRE(fprintf(output, "%s", contents) > 0); + fclose(output); + + /* The ATF C library provides more than just macros to verify the + * outcome of expressions. It also includes various helper functions + * to work with files and processes. Here is just a simple + * example. */ + ATF_REQUIRE(atf_utils_compare_file("test.txt", contents)); + + /* Of special note here is that we are NOT deleting the + * temporary files we created in this test. Kyua takes care of + * this cleanup automatically and tests can (and should) rely on + * this behavior. */ +} + +/* + * Lastly, we tell ATF which test cases exist in this program. This + * function should not do anything other than this registration. + */ +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, snprintf__two_formatters); + ATF_TP_ADD_TC(tp, snprintf__overflow); + ATF_TP_ADD_TC(tp, fprintf__simple_string); + + return (atf_no_error()); +} diff --git a/share/examples/tests/tests/googletest/Makefile b/share/examples/tests/tests/googletest/Makefile new file mode 100644 index 000000000000..57bfc3a12dff --- /dev/null +++ b/share/examples/tests/tests/googletest/Makefile @@ -0,0 +1,58 @@ +# +# This Makefile differs from the other examples, in the sense that its purpose +# is to install the upstream provided googletest sample unit tests. + +# The release package to use for the tests contained within the directory +# +# This applies to components which rely on ^/projects/release-pkg support +# (see UPDATING XXXXXXXXX / svn revision r298107). +PACKAGE= tests + +# Directory into which the Kyuafile provided by this directory will be +# installed. +# +# This is always a subdirectory of ${TESTSBASE}/. The remainder of the +# path has to match the relative path within the source tree in which +# these files are found modulo the tests/ component at the end. +# +# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR +# would point at ${TESTSBASE}/bin/cp/. +TESTSDIR= ${TESTSBASE}/share/examples/tests/googletest + +.PATH: ${SRCTOP}/contrib/googletest/googletest/samples + +GTEST_MAIN_REQ_TESTS+= sample1_unittest +GTEST_MAIN_REQ_TESTS+= sample2_unittest +GTEST_MAIN_REQ_TESTS+= sample3_unittest +GTEST_MAIN_REQ_TESTS+= sample4_unittest +GTEST_MAIN_REQ_TESTS+= sample5_unittest +GTEST_MAIN_REQ_TESTS+= sample6_unittest +GTEST_MAIN_REQ_TESTS+= sample7_unittest +GTEST_MAIN_REQ_TESTS+= sample8_unittest + +# sample9_unittest's `CustomOutputTest.Fails` fails intentionally to illustrate +# how output format can be adjusted with command-line parameters. +#GTEST_REQ_TESTS+= sample9_unittest +GTEST_REQ_TESTS+= sample10_unittest + +# List of test programs to build. Note that we can build more than one +# test from a single directory, and this is expected. +GTESTS+= ${GTEST_MAIN_REQ_TESTS} ${GTEST_REQ_TESTS} + +# +.for t in ${GTESTS} +.if ${GTEST_MAIN_REQ_TESTS:M$t} +LIBADD.$t+= gtest_main +.else +LIBADD.$t+= gtest +.endif +SRCS.$t+= $t.cc +.endfor + +# Additional sources for sample testcase 1, 2, 4, and 5. +SRCS.sample1_unittest+= sample1.cc +SRCS.sample2_unittest+= sample2.cc +SRCS.sample4_unittest+= sample4.cc +SRCS.sample5_unittest+= sample1.cc + +.include <bsd.test.mk> diff --git a/share/examples/tests/tests/plain/Kyuafile b/share/examples/tests/tests/plain/Kyuafile new file mode 100644 index 000000000000..c427a6045e95 --- /dev/null +++ b/share/examples/tests/tests/plain/Kyuafile @@ -0,0 +1,46 @@ +-- +-- Copyright 2013 Google Inc. +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are +-- met: +-- +-- * Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- * Neither the name of Google Inc. nor the names of its contributors +-- may be used to endorse or promote products derived from this software +-- without specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax(2) + +-- All tests provided by the FreeBSD base system should set the test_suite +-- property to FreeBSD. This creates a namespace in the configuration file +-- in which specific run-time properties can be passed to the tests below. +test_suite('FreeBSD') + +-- Register the various test programs into the test suite defined in this +-- directory. +-- +-- Because plain test programs cannot define metadata in their code (they +-- have no mechanism to communicate that to Kyua), we can instead define +-- any metadata properties in here. These have the exact same meaning as +-- their ATF counterparts. These properties are often useful to define +-- prerequisites for the execution of the tests. +plain_test_program{name='cp_test', required_programs='/bin/cp'} +plain_test_program{name='printf_test'} diff --git a/share/examples/tests/tests/plain/Makefile b/share/examples/tests/tests/plain/Makefile new file mode 100644 index 000000000000..462324309f6a --- /dev/null +++ b/share/examples/tests/tests/plain/Makefile @@ -0,0 +1,52 @@ + +# The release package to use for the tests contained within the directory +# +# This applies to components which rely on ^/projects/release-pkg support +# (see UPDATING XXXXXXXXX / svn revision r298107). +PACKAGE= tests + +# Directory into which the Kyuafile provided by this directory will be +# installed. +# +# This is always a subdirectory of ${TESTSBASE}/. The remainder of the +# path has to match the relative path within the source tree in which +# these files are found modulo the tests/ component at the end. +# +# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR +# would point at ${TESTSBASE}/bin/cp/. +TESTSDIR= ${TESTSBASE}/share/examples/tests/plain + +# List of test programs to build. Note that we can build more than one +# test from a single directory, and this is expected. +PLAIN_TESTS_C= printf_test +PLAIN_TESTS_SH= cp_test + +# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this +# directory. We do so because the file in this directory exists for +# documentation purposes. +# +# In general, however, you should NOT define KYUAFILE at all to allow +# bsd.test.mk auto-generate one for you based on the PLAIN_TESTS_* +# definitions from above. +KYUAFILE= yes + +# Install file1 and file2 as files via bsd.progs.mk. Please note the intentional +# ${PACKAGE} namespace of files. +# +# The basic semantics of this are the same as FILES in bsd.progs.mk, e.g. the +# installation of the files can be manipulated via ${PACKAGE}FILESDIR, +# ${PACKAGE}FILESMODE, etc. +# +# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE} +# namespace if release package support isn't needed. +${PACKAGE}FILES+= file1 +CLEANFILES+= file1 + +file1: + @echo "File 1" > ${.TARGET} + +.include <bsd.test.mk> + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/examples/tests/tests/plain/Makefile.depend b/share/examples/tests/tests/plain/Makefile.depend new file mode 100644 index 000000000000..84b8ddd67e34 --- /dev/null +++ b/share/examples/tests/tests/plain/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/tests/tests/plain/cp_test.sh b/share/examples/tests/tests/plain/cp_test.sh new file mode 100644 index 000000000000..d7c813d504b2 --- /dev/null +++ b/share/examples/tests/tests/plain/cp_test.sh @@ -0,0 +1,83 @@ +#! /bin/sh +# +# Copyright 2013 Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of Google Inc. nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# +# INTRODUCTION +# +# This plain test program mimics the structure and contents of its +# ATF-based counterpart. It attempts to represent various test cases +# in different separate functions and just calls them all from main. +# +# In reality, plain test programs can be much simpler. All they have +# to do is return 0 on success and non-0 otherwise. +# + +set -e + +# Prints an error message and exits. +err() { + echo "${@}" 1>&2 + exit 1 +} + +# Auxiliary function to compare two files for equality. +verify_copy() { + if ! cmp -s "${1}" "${2}"; then + diff -u "${1}" "${2}" + err "${1} and ${2} differ, but they should be equal" + fi +} + +simple_test() { + cp "$(dirname "${0}")/file1" . + cp file1 file2 || err "cp failed" + verify_copy file1 file2 +} + +force_test() { + echo 'File 3' >file3 + chmod 400 file3 + cp -f file1 file3 || err "cp failed" + verify_copy file1 file3 +} + +# If you have read the cp_test.sh counterpart in the atf/ directory, you +# may think that the sequencing of tests below and the exposed behavior +# to the user is very similar. But you'd be wrong. +# +# There are two major differences with this and the ATF version. The +# first is that the code below has no provisions to detect failures in +# one test and continue running the other tests: the first failure +# causes the whole test program to exit. The second is that this +# particular "main" has no arguments: without ATF, all test programs may +# expose a different command-line interface, and this is an issue for +# consistency purposes. +simple_test +force_test diff --git a/share/examples/tests/tests/plain/printf_test.c b/share/examples/tests/tests/plain/printf_test.c new file mode 100644 index 000000000000..09c46086a58b --- /dev/null +++ b/share/examples/tests/tests/plain/printf_test.c @@ -0,0 +1,121 @@ + +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright 2013 Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* + * INTRODUCTION + * + * This plain test program mimics the structure and contents of its + * ATF-based counterpart. It attempts to represent various test cases + * in different separate functions and just calls them all from main(). + * + * In reality, plain test programs can be much simpler. All they have + * to do is return 0 on success and non-0 otherwise. + */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void +snprintf__two_formatters(void) +{ + char buffer[128]; + + if (snprintf(buffer, sizeof(buffer), "%s, %s!", "Hello", + "tests") <= 0) + errx(EXIT_FAILURE, "snprintf with two formatters failed"); + + if (strcmp(buffer, "Hello, tests!") != 0) + errx(EXIT_FAILURE, "Bad formatting: got %s", buffer); +} + +static void +snprintf__overflow(void) +{ + char buffer[10]; + + if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16) + errx(EXIT_FAILURE, "snprintf did not return the expected " + "number of characters"); + + if (strcmp(buffer, "012345678") != 0) + errx(EXIT_FAILURE, "Bad formatting: got %s", buffer); +} + +static void +fprintf__simple_string(void) +{ + FILE *file; + char buffer[128]; + size_t length; + const char *contents = "This is a message\n"; + + file = fopen("test.txt", "w+"); + if (fprintf(file, "%s", contents) <= 0) + err(EXIT_FAILURE, "fprintf failed to write to file"); + rewind(file); + length = fread(buffer, 1, sizeof(buffer) - 1, file); + if (length != strlen(contents)) + err(EXIT_FAILURE, "fread failed"); + buffer[length] = '\0'; + fclose(file); + + if (strcmp(buffer, contents) != 0) + errx(EXIT_FAILURE, "Written and read data differ"); + + /* Of special note here is that we are NOT deleting the temporary + * files we created in this test. Kyua takes care of this cleanup + * automatically and tests can (and should) rely on this behavior. */ +} + +int +main(void) +{ + /* If you have read the printf_test.c counterpart in the atf/ + * directory, you may think that the sequencing of tests below and + * the exposed behavior to the user is very similar. But you'd be + * wrong. + * + * There are two major differences with this and the ATF version. + * The first is that the code below has no provisions to detect + * failures in one test and continue running the other tests: the + * first failure causes the whole test program to exit. The second + * is that this particular main() has no arguments: without ATF, + * all test programs may expose a different command-line interface, + * and this is an issue for consistency purposes. */ + snprintf__two_formatters(); + snprintf__overflow(); + fprintf__simple_string(); + + return EXIT_SUCCESS; +} diff --git a/share/examples/tests/tests/tap/Kyuafile b/share/examples/tests/tests/tap/Kyuafile new file mode 100644 index 000000000000..64339c54c012 --- /dev/null +++ b/share/examples/tests/tests/tap/Kyuafile @@ -0,0 +1,46 @@ +-- +-- Copyright 2013 Google Inc. +-- All rights reserved. +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions are +-- met: +-- +-- * Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- * Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- * Neither the name of Google Inc. nor the names of its contributors +-- may be used to endorse or promote products derived from this software +-- without specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +-- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax(2) + +-- All tests provided by the FreeBSD base system should set the test_suite +-- property to FreeBSD. This creates a namespace in the configuration file +-- in which specific run-time properties can be passed to the tests below. +test_suite('FreeBSD') + +-- Register the various test programs into the test suite defined in this +-- directory. +-- +-- Because plain test programs cannot define metadata in their code (they +-- have no mechanism to communicate that to Kyua), we can instead define +-- any metadata properties in here. These have the exact same meaning as +-- their ATF counterparts. These properties are often useful to define +-- prerequisites for the execution of the tests. +tap_test_program{name='cp_test', required_programs='/bin/cp'} +tap_test_program{name='printf_test'} diff --git a/share/examples/tests/tests/tap/Makefile b/share/examples/tests/tests/tap/Makefile new file mode 100644 index 000000000000..86d3f6805045 --- /dev/null +++ b/share/examples/tests/tests/tap/Makefile @@ -0,0 +1,52 @@ + +# The release package to use for the tests contained within the directory +# +# This applies to components which rely on ^/projects/release-pkg support +# (see UPDATING XXXXXXXXX / svn revision r298107). +PACKAGE= tests + +# Directory into which the Kyuafile provided by this directory will be +# installed. +# +# This is always a subdirectory of ${TESTSBASE}/. The remainder of the +# path has to match the relative path within the source tree in which +# these files are found modulo the tests/ component at the end. +# +# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR +# would point at ${TESTSBASE}/bin/cp/. +TESTSDIR= ${TESTSBASE}/share/examples/tests/tap + +# List of test programs to build. Note that we can build more than one +# test from a single directory, and this is expected. +TAP_TESTS_C= printf_test +TAP_TESTS_SH= cp_test + +# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this +# directory. We do so because the file in this directory exists for +# documentation purposes. +# +# In general, however, you should NOT define KYUAFILE at all to allow +# bsd.test.mk auto-generate one for you based on the PLAIN_TESTS_* +# definitions from above. +KYUAFILE= yes + +# Install file1 and file2 as files via bsd.prog.mk. Please note the intentional +# ${PACKAGE} namespace of files. +# +# The basic semantics of this are the same as FILES in bsd.prog.mk, e.g. the +# installation of the files can be manipulated via ${PACKAGE}FILESDIR, +# ${PACKAGE}FILESMODE, etc. +# +# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE} +# namespace if release package support isn't needed. +${PACKAGE}FILES+= file1 +CLEANFILES+= file1 + +file1: + @echo "File 1" > ${.TARGET} + +.include <bsd.test.mk> + +.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000 +CWARNFLAGS.printf_test.c+= -Wno-format-truncation +.endif diff --git a/share/examples/tests/tests/tap/Makefile.depend b/share/examples/tests/tests/tap/Makefile.depend new file mode 100644 index 000000000000..84b8ddd67e34 --- /dev/null +++ b/share/examples/tests/tests/tap/Makefile.depend @@ -0,0 +1,16 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/tests/tests/tap/cp_test.sh b/share/examples/tests/tests/tap/cp_test.sh new file mode 100644 index 000000000000..118c2001ae71 --- /dev/null +++ b/share/examples/tests/tests/tap/cp_test.sh @@ -0,0 +1,97 @@ +#!/bin/sh +# +# Copyright (c) 2017 Enji Cooper <ngie@FreeBSD.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# + +# +# INTRODUCTION +# +# This TAP test program mimics the structure and contents of its +# ATF-based counterpart. It attempts to represent various test cases +# in different separate functions and just calls them all from main. +# + +test_num=1 +TEST_COUNT=4 + +result() +{ + local result=$1; shift + local result_string + + result_string="$result $test_num" + if [ $# -gt 0 ]; then + result_string="$result_string - $@" + fi + echo "$result_string" + : $(( test_num += 1 )) +} + +# Auxiliary function to compare two files for equality. +verify_copy() { + if cmp -s "${1}" "${2}"; then + result "ok" + else + result "not ok" "${1} and ${2} differ, but they should be equal" + diff -u "${1}" "${2}" + fi +} + +simple_test() { + cp "$(dirname "${0}")/file1" . + if cp file1 file2; then + result "ok" + verify_copy file1 file2 + else + result "not ok" "cp failed" + result "not ok" "# SKIP" + fi +} + +force_test() { + echo 'File 3' >file3 + chmod 400 file3 + if cp -f file1 file3; then + result "ok" + verify_copy file1 file3 + else + result "not ok" "cp -f failed" + result "not ok" "# SKIP" + fi +} + +# If you have read the cp_test.sh counterpart in the atf/ directory, you +# may think that the sequencing of tests below and the exposed behavior +# to the user is very similar. But you'd be wrong. +# +# There are two major differences with this and the ATF version. First off, +# the TAP test doesn't isolate simple_test from force_test, whereas the ATF +# version does. Secondly, the test script accepts arbitrary command line +# inputs. +echo "1..$TEST_COUNT" + +simple_test +force_test +exit 0 diff --git a/share/examples/tests/tests/tap/printf_test.c b/share/examples/tests/tests/tap/printf_test.c new file mode 100644 index 000000000000..62ab64722f8b --- /dev/null +++ b/share/examples/tests/tests/tap/printf_test.c @@ -0,0 +1,184 @@ +/* + * Copyright 2013 Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* + * INTRODUCTION + * + * This plain test program mimics the structure and contents of its + * ATF-based counterpart. It attempts to represent various test cases + * in different separate functions and just calls them all from main(). + * + * In reality, plain test programs can be much simpler. All they have + * to do is return 0 on success and non-0 otherwise. + */ + +#include <err.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static int failed; +static int test_num = 1; + +#define TEST_COUNT 7 + +static void +fail(const char *fmt, ...) +{ + char *msg; + va_list ap; + + failed = 1; + + va_start(ap, fmt); + if (vasprintf(&msg, fmt, ap) == -1) + err(1, NULL); + va_end(ap); + printf("not ok %d - %s\n", test_num, msg); + free(msg); + + test_num++; +} + +static void +pass(void) +{ + + printf("ok %d\n", test_num); + test_num++; +} + +static void +skip(int skip_num) +{ + int i; + + for (i = 0; i < skip_num; i++) { + printf("not ok %d # SKIP\n", test_num); + test_num++; + } +} + +static void +snprintf__two_formatters(void) +{ + char buffer[128]; + + if (snprintf(buffer, sizeof(buffer), "%s, %s!", "Hello", + "tests") <= 0) { + fail("snprintf with two formatters failed"); + skip(1); + } else { + pass(); + if (strcmp(buffer, "Hello, tests!") != 0) + fail("Bad formatting: got %s", buffer); + else + pass(); + } +} + +static void +snprintf__overflow(void) +{ + char buffer[10]; + + if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16) { + fail("snprintf did not return the expected " + "number of characters"); + skip(1); + return; + } + pass(); + + if (strcmp(buffer, "012345678") != 0) + fail("Bad formatting: got %s", buffer); + else + pass(); +} + +static void +fprintf__simple_string(void) +{ + FILE *file; + char buffer[128]; + size_t length; + const char *contents = "This is a message\n"; + + file = fopen("test.txt", "w+"); + if (fprintf(file, "%s", contents) <= 0) { + fail("fprintf failed to write to file"); + skip(2); + return; + } + pass(); + rewind(file); + length = fread(buffer, 1, sizeof(buffer) - 1, file); + if (length != strlen(contents)) { + fail("fread failed"); + skip(1); + return; + } + pass(); + buffer[length] = '\0'; + fclose(file); + + if (strcmp(buffer, contents) != 0) + fail("Written and read data differ"); + else + pass(); + + /* Of special note here is that we are NOT deleting the temporary + * files we created in this test. Kyua takes care of this cleanup + * automatically and tests can (and should) rely on this behavior. */ +} + +int +main(void) +{ + /* If you have read the printf_test.c counterpart in the atf/ + * directory, you may think that the sequencing of tests below and + * the exposed behavior to the user is very similar. But you'd be + * wrong. + * + * There are two major differences with this and the ATF version. + * The first is that the code below has no provisions to detect + * failures in one test and continue running the other tests: the + * first failure causes the whole test program to exit. The second + * is that this particular main() has no arguments: without ATF, + * all test programs may expose a different command-line interface, + * and this is an issue for consistency purposes. */ + printf("1..%d\n", TEST_COUNT); + + snprintf__two_formatters(); + snprintf__overflow(); + fprintf__simple_string(); + + return (failed); +} diff --git a/share/examples/uefisign/uefikeys b/share/examples/uefisign/uefikeys new file mode 100755 index 000000000000..ac97f2cfb3fa --- /dev/null +++ b/share/examples/uefisign/uefikeys @@ -0,0 +1,36 @@ +#!/bin/sh +# +# See uefisign(8) manual page for usage instructions. +# +# + +die() { + echo "$*" > /dev/stderr + exit 1 +} + +if [ $# -ne 1 ]; then + echo "usage: $0 common-name" + exit 1 +fi + +certfile="${1}.pem" +efifile="${1}.cer" +keyfile="${1}.key" +# XXX: Set this to ten years; we don't want system to suddenly stop booting +# due to certificate expiration. Better way would be to use Authenticode +# Timestamp. That said, the rumor is UEFI implementations ignore it anyway. +days="3650" +subj="/CN=${1}" + +[ ! -e "${certfile}" ] || die "${certfile} already exists" +[ ! -e "${efifile}" ] || die "${efifile} already exists" +[ ! -e "${keyfile}" ] || die "${keyfile} already exists" + +umask 077 || die "umask 077 failed" + +openssl genrsa -out "${keyfile}" 2048 2> /dev/null || die "openssl genrsa failed" +openssl req -new -x509 -sha256 -days "${days}" -subj "${subj}" -key "${keyfile}" -out "${certfile}" || die "openssl req failed" +openssl x509 -inform PEM -outform DER -in "${certfile}" -out "${efifile}" || die "openssl x509 failed" + +echo "certificate: ${certfile}; private key: ${keyfile}; certificate to enroll in UEFI: ${efifile}" diff --git a/share/examples/witness/lockgraphs.sh b/share/examples/witness/lockgraphs.sh new file mode 100644 index 000000000000..cbb229228273 --- /dev/null +++ b/share/examples/witness/lockgraphs.sh @@ -0,0 +1,23 @@ +#!/bin/sh +################################################################################ +# +# lockgraphs.sh by Michele Dallachiesa -- 2008-05-07 -- v0.1 +# +# +################################################################################ + +sysctl debug.witness.graphs | awk ' +BEGIN { + print "digraph lockgraphs {" + } + +NR > 1 && $0 ~ /"Giant"/ { + gsub(","," -> "); + print $0 ";" +} + +END { + print "}" + }' + +#eof diff --git a/share/examples/ypldap/ypldap.conf b/share/examples/ypldap/ypldap.conf new file mode 100644 index 000000000000..46c6cf0d83eb --- /dev/null +++ b/share/examples/ypldap/ypldap.conf @@ -0,0 +1,39 @@ +domain "freebsd.org" +interval 60 +provide map "passwd.byname" +provide map "passwd.byuid" +provide map "group.byname" +provide map "group.bygid" +provide map "netid.byname" + +directory "127.0.0.1" { + # directory options + binddn "cn=ldap,dc=freebsd,dc=org" + bindcred "secret" + basedn "dc=freebsd.,dc=org" + # starting point for groups directory search, default to basedn + groupdn "ou=Groups,dc=freebsd,dc=org" + + # passwd maps configuration (RFC 2307 posixAccount object class) + passwd filter "(objectClass=posixAccount)" + + attribute name maps to "uid" + fixed attribute passwd "*" + attribute uid maps to "uidNumber" + attribute gid maps to "gidNumber" + attribute gecos maps to "cn" + attribute home maps to "homeDirectory" + attribute shell maps to "loginShell" + fixed attribute change "0" + fixed attribute expire "0" + fixed attribute class "" + + # group maps configuration (RFC 2307 posixGroup object class) + group filter "(objectClass=posixGroup)" + + attribute groupname maps to "cn" + fixed attribute grouppasswd "*" + attribute groupgid maps to "gidNumber" + # memberUid returns multiple group members + list groupmembers maps to "memberUid" +} |