1370007Sdonner/*- 2370007Sdonner * SPDX-License-Identifier: BSD-3-Clause 3370007Sdonner * 4370007Sdonner * Copyright 2021 Lutz Donnerhacke 5370007Sdonner * 6370007Sdonner * Redistribution and use in source and binary forms, with or without 7370007Sdonner * modification, are permitted provided that the following conditions 8370007Sdonner * are met: 9370007Sdonner * 10370007Sdonner * 1. Redistributions of source code must retain the above copyright 11370007Sdonner * notice, this list of conditions and the following disclaimer. 12370007Sdonner * 2. Redistributions in binary form must reproduce the above 13370007Sdonner * copyright notice, this list of conditions and the following 14370007Sdonner * disclaimer in the documentation and/or other materials provided 15370007Sdonner * with the distribution. 16370007Sdonner * 3. Neither the name of the copyright holder nor the names of its 17370007Sdonner * contributors may be used to endorse or promote products derived 18370007Sdonner * from this software without specific prior written permission. 19370007Sdonner * 20370007Sdonner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 21370007Sdonner * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 22370007Sdonner * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23370007Sdonner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24370007Sdonner * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 25370007Sdonner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26370007Sdonner * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27370007Sdonner * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28370007Sdonner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29370007Sdonner * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30370007Sdonner * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 31370007Sdonner * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32370007Sdonner * SUCH DAMAGE. 33370007Sdonner */ 34370007Sdonner#include <atf-c.h> 35370007Sdonner#include <errno.h> 36370007Sdonner#include <stdio.h> 37370007Sdonner 38370007Sdonner#include <net/ethernet.h> 39370007Sdonner#include <netinet/in.h> 40370007Sdonner#include <netinet/ip.h> 41370007Sdonner#include <netinet/ip6.h> 42370007Sdonner 43370007Sdonner#include "util.h" 44370007Sdonner#include <netgraph/ng_bridge.h> 45370007Sdonner 46370007Sdonnerstatic void get_tablesize(char const *source, struct ng_mesg *msg, void *ctx); 47370007Sdonnerstruct gettable 48370007Sdonner{ 49370007Sdonner u_int32_t tok; 50370007Sdonner int cnt; 51370007Sdonner}; 52370007Sdonner 53370007Sdonnerstruct frame4 54370007Sdonner{ 55370007Sdonner struct ether_header eh; 56370007Sdonner struct ip ip; 57370007Sdonner char data[64]; 58370007Sdonner}; 59370007Sdonnerstruct frame6 60370007Sdonner{ 61370007Sdonner struct ether_header eh; 62370007Sdonner struct ip6_hdr ip; 63370007Sdonner char data[64]; 64370007Sdonner}; 65370007Sdonner 66370007Sdonnerstatic struct frame4 msg4 = { 67370007Sdonner .ip.ip_v = 4, 68370007Sdonner .ip.ip_hl = 5, 69370007Sdonner .ip.ip_ttl = 1, 70370007Sdonner .ip.ip_p = 254, 71370007Sdonner .ip.ip_src = {htonl(0x0a00dead)}, 72370007Sdonner .ip.ip_dst = {htonl(0x0a00beef)}, 73370007Sdonner .ip.ip_len = 32, 74370007Sdonner .eh.ether_type = ETHERTYPE_IP, 75370007Sdonner .eh.ether_shost = {2, 4, 6}, 76370007Sdonner .eh.ether_dhost = {2, 4, 6}, 77370007Sdonner}; 78370007Sdonner 79370007Sdonner 80370007SdonnerATF_TC(basic); 81370007SdonnerATF_TC_HEAD(basic, conf) 82370007Sdonner{ 83370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 84370007Sdonner} 85370007Sdonner 86370007SdonnerATF_TC_BODY(basic, dummy) 87370007Sdonner{ 88370007Sdonner ng_counter_t r; 89370007Sdonner struct gettable rm; 90370007Sdonner 91370007Sdonner ng_init(); 92370007Sdonner ng_errors(PASS); 93370007Sdonner ng_shutdown("bridge:"); 94370007Sdonner ng_errors(FAIL); 95370007Sdonner 96370007Sdonner ng_mkpeer(".", "a", "bridge", "link0"); 97370007Sdonner ng_name("a", "bridge"); 98370007Sdonner ng_connect(".", "b", "bridge:", "link1"); 99370007Sdonner ng_connect(".", "c", "bridge:", "link2"); 100370007Sdonner 101370007Sdonner /* do not bounce back */ 102370007Sdonner ng_register_data("a", get_data0); 103370007Sdonner ng_counter_clear(r); 104370007Sdonner msg4.eh.ether_shost[5] = 1; 105370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 106370007Sdonner ng_handle_events(50, &r); 107370007Sdonner ATF_CHECK(r[0] == 0); 108370007Sdonner 109370007Sdonner /* send to others */ 110370007Sdonner ng_register_data("b", get_data1); 111370007Sdonner ng_register_data("c", get_data2); 112370007Sdonner ng_counter_clear(r); 113370007Sdonner msg4.eh.ether_shost[5] = 1; 114370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 115370007Sdonner ng_handle_events(50, &r); 116370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1); 117370007Sdonner 118370007Sdonner ng_counter_clear(r); 119370007Sdonner msg4.eh.ether_shost[5] = 2; 120370007Sdonner ng_send_data("b", &msg4, sizeof(msg4)); 121370007Sdonner ng_handle_events(50, &r); 122370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1); 123370007Sdonner 124370007Sdonner ng_counter_clear(r); 125370007Sdonner msg4.eh.ether_shost[5] = 3; 126370007Sdonner ng_send_data("c", &msg4, sizeof(msg4)); 127370007Sdonner ng_handle_events(50, &r); 128370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 1 && r[2] == 0); 129370007Sdonner 130370007Sdonner /* send to learned unicast */ 131370007Sdonner ng_counter_clear(r); 132370007Sdonner msg4.eh.ether_shost[5] = 1; 133370007Sdonner msg4.eh.ether_dhost[5] = 3; 134370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 135370007Sdonner ng_handle_events(50, &r); 136370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1); 137370007Sdonner 138370007Sdonner /* inspect mac table */ 139370007Sdonner ng_register_msg(get_tablesize); 140370007Sdonner rm.tok = ng_send_msg("bridge:", "gettable"); 141370007Sdonner rm.cnt = 0; 142370007Sdonner ng_handle_events(50, &rm); 143370007Sdonner ATF_CHECK(rm.cnt == 3); 144370007Sdonner 145370007Sdonner /* remove a link */ 146370007Sdonner ng_rmhook(".", "b"); 147370007Sdonner ng_counter_clear(r); 148370007Sdonner msg4.eh.ether_shost[5] = 1; 149370007Sdonner msg4.eh.ether_dhost[5] = 0; 150370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 151370007Sdonner ng_handle_events(50, &r); 152370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1); 153370007Sdonner 154370007Sdonner /* inspect mac table */ 155370007Sdonner ng_register_msg(get_tablesize); 156370007Sdonner rm.tok = ng_send_msg("bridge:", "gettable"); 157370007Sdonner rm.cnt = 0; 158370007Sdonner ng_handle_events(50, &rm); 159370007Sdonner ATF_CHECK(rm.cnt == 2); 160370007Sdonner 161370007Sdonner ng_shutdown("bridge:"); 162370007Sdonner} 163370007Sdonner 164370007SdonnerATF_TC(persistence); 165370007SdonnerATF_TC_HEAD(persistence, conf) 166370007Sdonner{ 167370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 168370007Sdonner} 169370007Sdonner 170370007SdonnerATF_TC_BODY(persistence, dummy) 171370007Sdonner{ 172370007Sdonner ng_init(); 173370007Sdonner ng_errors(PASS); 174370007Sdonner ng_shutdown("bridge:"); 175370007Sdonner ng_errors(FAIL); 176370007Sdonner 177370007Sdonner ng_mkpeer(".", "a", "bridge", "link0"); 178370007Sdonner ng_name("a", "bridge"); 179370007Sdonner 180370007Sdonner ng_send_msg("bridge:", "setpersistent"); 181370007Sdonner ng_rmhook(".", "a"); 182370007Sdonner 183370007Sdonner ng_shutdown("bridge:"); 184370007Sdonner} 185370007Sdonner 186370007SdonnerATF_TC(loop); 187370007SdonnerATF_TC_HEAD(loop, conf) 188370007Sdonner{ 189370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 190370007Sdonner} 191370007Sdonner 192370007SdonnerATF_TC_BODY(loop, dummy) 193370007Sdonner{ 194370007Sdonner ng_counter_t r; 195370007Sdonner int i; 196370007Sdonner 197370007Sdonner ng_init(); 198370007Sdonner ng_errors(PASS); 199370007Sdonner ng_shutdown("bridge1:"); 200370007Sdonner ng_shutdown("bridge2:"); 201370007Sdonner ng_errors(FAIL); 202370007Sdonner 203370007Sdonner ng_mkpeer(".", "a", "bridge", "link0"); 204370007Sdonner ng_name("a", "bridge1"); 205370007Sdonner ng_mkpeer(".", "b", "bridge", "link1"); 206370007Sdonner ng_name("b", "bridge2"); 207370007Sdonner 208370007Sdonner ng_register_data("a", get_data0); 209370007Sdonner ng_register_data("b", get_data1); 210370007Sdonner 211370007Sdonner /*- 212370007Sdonner * Open loop 213370007Sdonner * 214370007Sdonner * /-- bridge1 215370007Sdonner * . < | 216370007Sdonner * \-- bridge2 217370007Sdonner */ 218370007Sdonner ng_connect("bridge1:", "link11", "bridge2:", "link11"); 219370007Sdonner 220370007Sdonner ng_counter_clear(r); 221370007Sdonner msg4.eh.ether_shost[5] = 1; 222370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 223370007Sdonner ng_handle_events(50, &r); 224370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1); 225370007Sdonner 226370007Sdonner /*- 227370007Sdonner * Closed loop, DANGEROUS! 228370007Sdonner * 229370007Sdonner * /-- bridge1 -\ 230370007Sdonner * . < | | 231370007Sdonner * \-- bridge2 -/ 232370007Sdonner */ 233370007Sdonner ng_connect("bridge1:", "link12", "bridge2:", "link12"); 234370007Sdonner 235370007Sdonner ng_counter_clear(r); 236370007Sdonner msg4.eh.ether_shost[5] = 1; 237370007Sdonner ng_errors(PASS); 238370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 239370007Sdonner ATF_CHECK_ERRNO(ELOOP, errno != 0); /* loop might be detected */ 240370007Sdonner ng_errors(FAIL); 241370007Sdonner for (i = 0; i < 10; i++) /* don't run forever */ 242370007Sdonner if (!ng_handle_event(50, &r)) 243370007Sdonner break; 244370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1); 245370007Sdonner 246370007Sdonner ng_shutdown("bridge1:"); 247370007Sdonner ng_shutdown("bridge2:"); 248370007Sdonner} 249370007Sdonner 250370007SdonnerATF_TC(many_unicasts); 251370007SdonnerATF_TC_HEAD(many_unicasts, conf) 252370007Sdonner{ 253370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 254370007Sdonner} 255370007Sdonner 256370007SdonnerATF_TC_BODY(many_unicasts, dummy) 257370007Sdonner{ 258370007Sdonner ng_counter_t r; 259370007Sdonner int i; 260370007Sdonner const int HOOKS = 1000; 261370007Sdonner struct gettable rm; 262370007Sdonner 263370007Sdonner ng_init(); 264370007Sdonner ng_errors(PASS); 265370007Sdonner ng_shutdown("bridge:"); 266370007Sdonner ng_errors(FAIL); 267370007Sdonner 268370007Sdonner ng_mkpeer(".", "a", "bridge", "link0"); 269370007Sdonner ng_name("a", "bridge"); 270370007Sdonner ng_register_data("a", get_data0); 271370007Sdonner 272370007Sdonner /* learn MAC */ 273370007Sdonner ng_counter_clear(r); 274370007Sdonner msg4.eh.ether_shost[3] = 0xff; 275370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 276370007Sdonner ng_handle_events(50, &r); 277370007Sdonner ATF_CHECK(r[0] == 0); 278370007Sdonner 279370007Sdonner /* use learned MAC as destination */ 280370007Sdonner msg4.eh.ether_shost[3] = 0; 281370007Sdonner msg4.eh.ether_dhost[3] = 0xff; 282370007Sdonner 283370007Sdonner /* now send */ 284370007Sdonner ng_counter_clear(r); 285370007Sdonner for (i = 1; i <= HOOKS; i++) 286370007Sdonner { 287370007Sdonner char hook[20]; 288370007Sdonner 289370007Sdonner snprintf(hook, sizeof(hook), "link%d", i); 290370007Sdonner ng_connect(".", hook, "bridge:", hook); 291370007Sdonner ng_register_data(hook, get_data2); 292370007Sdonner 293370007Sdonner msg4.eh.ether_shost[4] = i >> 8; 294370007Sdonner msg4.eh.ether_shost[5] = i & 0xff; 295370007Sdonner ng_errors(PASS); 296370007Sdonner ng_send_data(hook, &msg4, sizeof(msg4)); 297370007Sdonner ng_errors(FAIL); 298370007Sdonner if (errno != 0) 299370007Sdonner break; 300370007Sdonner ng_handle_events(50, &r); 301370007Sdonner } 302370007Sdonner ATF_CHECK(r[0] == HOOKS && r[2] == 0); 303370007Sdonner 304370007Sdonner /* inspect mac table */ 305370007Sdonner ng_register_msg(get_tablesize); 306370007Sdonner rm.cnt = 0; 307370007Sdonner ng_errors(PASS); 308370007Sdonner rm.tok = ng_send_msg("bridge:", "gettable"); 309370007Sdonner ng_errors(FAIL); 310370007Sdonner if (rm.tok == (u_int32_t)-1) 311370007Sdonner { 312370007Sdonner ATF_CHECK_ERRNO(ENOBUFS, 1); 313370007Sdonner atf_tc_expect_fail("response too large"); 314370007Sdonner } 315370007Sdonner ng_handle_events(50, &rm); 316370007Sdonner ATF_CHECK(rm.cnt == HOOKS + 1); 317370007Sdonner atf_tc_expect_pass(); 318370007Sdonner 319370007Sdonner ng_shutdown("bridge:"); 320370007Sdonner} 321370007Sdonner 322370007SdonnerATF_TC(many_broadcasts); 323370007SdonnerATF_TC_HEAD(many_broadcasts, conf) 324370007Sdonner{ 325370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 326370007Sdonner} 327370007Sdonner 328370007SdonnerATF_TC_BODY(many_broadcasts, dummy) 329370007Sdonner{ 330370007Sdonner ng_counter_t r; 331370007Sdonner int i; 332370007Sdonner const int HOOKS = 1000; 333370007Sdonner 334370007Sdonner ng_init(); 335370007Sdonner ng_errors(PASS); 336370007Sdonner ng_shutdown("bridge:"); 337370007Sdonner ng_errors(FAIL); 338370007Sdonner 339370007Sdonner ng_mkpeer(".", "a", "bridge", "link0"); 340370007Sdonner ng_name("a", "bridge"); 341370007Sdonner ng_register_data("a", get_data0); 342370007Sdonner 343370007Sdonner /* learn MAC */ 344370007Sdonner ng_counter_clear(r); 345370007Sdonner msg4.eh.ether_shost[3] = 0xff; 346370007Sdonner ng_send_data("a", &msg4, sizeof(msg4)); 347370007Sdonner ng_handle_events(50, &r); 348370007Sdonner ATF_CHECK(r[0] == 0); 349370007Sdonner 350370007Sdonner /* use broadcast MAC */ 351370007Sdonner msg4.eh.ether_shost[3] = 0; 352370007Sdonner memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); 353370007Sdonner 354370007Sdonner /* now send */ 355370007Sdonner ng_counter_clear(r); 356370007Sdonner for (i = 1; i <= HOOKS; i++) 357370007Sdonner { 358370007Sdonner char hook[20]; 359370007Sdonner 360370007Sdonner snprintf(hook, sizeof(hook), "link%d", i); 361370007Sdonner ng_connect(".", hook, "bridge:", hook); 362370007Sdonner ng_register_data(hook, get_data3); 363370007Sdonner 364370007Sdonner msg4.eh.ether_shost[4] = i >> 8; 365370007Sdonner msg4.eh.ether_shost[5] = i & 0xff; 366370007Sdonner ng_errors(PASS); 367370007Sdonner ng_send_data(hook, &msg4, sizeof(msg4)); 368370007Sdonner ng_errors(FAIL); 369370007Sdonner if (errno != 0) 370370007Sdonner break; 371370007Sdonner ng_handle_events(50, &r); 372370007Sdonner } 373370007Sdonner ATF_CHECK(r[0] > 100 && r[3] > 100); 374370007Sdonner if (i < HOOKS) 375370007Sdonner atf_tc_expect_fail("netgraph queue full (%d)", i); 376370007Sdonner ATF_CHECK(r[0] == HOOKS); 377370007Sdonner atf_tc_expect_pass(); 378370007Sdonner 379370007Sdonner ng_shutdown("bridge:"); 380370007Sdonner} 381370007Sdonner 382370007SdonnerATF_TC(uplink_private); 383370007SdonnerATF_TC_HEAD(uplink_private, conf) 384370007Sdonner{ 385370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 386370007Sdonner} 387370007Sdonner 388370007SdonnerATF_TC_BODY(uplink_private, dummy) 389370007Sdonner{ 390370007Sdonner ng_counter_t r; 391370007Sdonner struct gettable rm; 392370007Sdonner 393370007Sdonner ng_init(); 394370007Sdonner ng_errors(PASS); 395370007Sdonner ng_shutdown("bridge:"); 396370007Sdonner 397370007Sdonner ng_mkpeer(".", "u1", "bridge", "uplink1"); 398370007Sdonner if (errno > 0) 399370007Sdonner atf_tc_skip("uplinks are not supported."); 400370007Sdonner ng_errors(FAIL); 401370007Sdonner ng_name("u1", "bridge"); 402370007Sdonner ng_register_data("u1", get_data1); 403370007Sdonner ng_connect(".", "u2", "bridge:", "uplink2"); 404370007Sdonner ng_register_data("u2", get_data2); 405370007Sdonner ng_connect(".", "l0", "bridge:", "link0"); 406370007Sdonner ng_register_data("l0", get_data0); 407370007Sdonner ng_connect(".", "l3", "bridge:", "link3"); 408370007Sdonner ng_register_data("l3", get_data3); 409370007Sdonner 410370007Sdonner /* unknown unicast 0 from uplink1 */ 411370007Sdonner ng_counter_clear(r); 412370007Sdonner msg4.eh.ether_shost[5] = 1; 413370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 414370007Sdonner ng_handle_events(50, &r); 415370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0); 416370007Sdonner 417370007Sdonner /* unknown unicast 2 from link0 */ 418370007Sdonner ng_counter_clear(r); 419370007Sdonner msg4.eh.ether_shost[5] = 0; 420370007Sdonner msg4.eh.ether_dhost[5] = 2; 421370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 422370007Sdonner ng_handle_events(50, &r); 423370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0); 424370007Sdonner 425370007Sdonner /* known unicast 0 from uplink2 */ 426370007Sdonner ng_counter_clear(r); 427370007Sdonner msg4.eh.ether_shost[5] = 2; 428370007Sdonner msg4.eh.ether_dhost[5] = 0; 429370007Sdonner ng_send_data("u2", &msg4, sizeof(msg4)); 430370007Sdonner ng_handle_events(50, &r); 431370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); 432370007Sdonner 433370007Sdonner /* known unicast 0 from link3 */ 434370007Sdonner ng_counter_clear(r); 435370007Sdonner msg4.eh.ether_shost[5] = 3; 436370007Sdonner msg4.eh.ether_dhost[5] = 0; 437370007Sdonner ng_send_data("l3", &msg4, sizeof(msg4)); 438370007Sdonner ng_handle_events(50, &r); 439370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); 440370007Sdonner 441370007Sdonner /* (un)known unicast 2 from uplink1 */ 442370007Sdonner ng_counter_clear(r); 443370007Sdonner msg4.eh.ether_shost[5] = 1; 444370007Sdonner msg4.eh.ether_dhost[5] = 2; 445370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 446370007Sdonner ng_handle_events(50, &r); 447370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0); 448370007Sdonner 449370007Sdonner /* (un)known unicast 2 from link0 */ 450370007Sdonner ng_counter_clear(r); 451370007Sdonner msg4.eh.ether_shost[5] = 0; 452370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 453370007Sdonner ng_handle_events(50, &r); 454370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0); 455370007Sdonner 456370007Sdonner /* unknown multicast 2 from uplink1 */ 457370007Sdonner ng_counter_clear(r); 458370007Sdonner msg4.eh.ether_shost[5] = 1; 459370007Sdonner msg4.eh.ether_dhost[0] = 0xff; 460370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 461370007Sdonner ng_handle_events(50, &r); 462370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 463370007Sdonner 464370007Sdonner /* unknown multicast 2 from link0 */ 465370007Sdonner ng_counter_clear(r); 466370007Sdonner msg4.eh.ether_shost[5] = 0; 467370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 468370007Sdonner ng_handle_events(50, &r); 469370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 470370007Sdonner 471370007Sdonner /* broadcast from uplink1 */ 472370007Sdonner ng_counter_clear(r); 473370007Sdonner msg4.eh.ether_shost[5] = 1; 474370007Sdonner memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); 475370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 476370007Sdonner ng_handle_events(50, &r); 477370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 478370007Sdonner 479370007Sdonner /* broadcast from link0 */ 480370007Sdonner ng_counter_clear(r); 481370007Sdonner msg4.eh.ether_shost[5] = 0; 482370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 483370007Sdonner ng_handle_events(50, &r); 484370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 485370007Sdonner 486370007Sdonner /* inspect mac table */ 487370007Sdonner ng_register_msg(get_tablesize); 488370007Sdonner rm.tok = ng_send_msg("bridge:", "gettable"); 489370007Sdonner rm.cnt = 0; 490370007Sdonner ng_handle_events(50, &rm); 491370007Sdonner ATF_CHECK(rm.cnt == 2); 492370007Sdonner 493370007Sdonner ng_shutdown("bridge:"); 494370007Sdonner} 495370007Sdonner 496370007SdonnerATF_TC(uplink_classic); 497370007SdonnerATF_TC_HEAD(uplink_classic, conf) 498370007Sdonner{ 499370007Sdonner atf_tc_set_md_var(conf, "require.user", "root"); 500370007Sdonner} 501370007Sdonner 502370007SdonnerATF_TC_BODY(uplink_classic, dummy) 503370007Sdonner{ 504370007Sdonner ng_counter_t r; 505370007Sdonner struct gettable rm; 506370007Sdonner 507370007Sdonner ng_init(); 508370007Sdonner ng_errors(PASS); 509370007Sdonner ng_shutdown("bridge:"); 510370007Sdonner 511370007Sdonner ng_mkpeer(".", "l0", "bridge", "link0"); 512370007Sdonner if (errno > 0) 513370007Sdonner atf_tc_skip("uplinks are not supported."); 514370007Sdonner ng_errors(FAIL); 515370007Sdonner ng_name("l0", "bridge"); 516370007Sdonner ng_register_data("l0", get_data0); 517370007Sdonner ng_connect(".", "u1", "bridge:", "uplink1"); 518370007Sdonner ng_register_data("u1", get_data1); 519370007Sdonner ng_connect(".", "u2", "bridge:", "uplink2"); 520370007Sdonner ng_register_data("u2", get_data2); 521370007Sdonner ng_connect(".", "l3", "bridge:", "link3"); 522370007Sdonner ng_register_data("l3", get_data3); 523370007Sdonner 524370007Sdonner /* unknown unicast 0 from uplink1 */ 525370007Sdonner ng_counter_clear(r); 526370007Sdonner msg4.eh.ether_shost[5] = 1; 527370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 528370007Sdonner ng_handle_events(50, &r); 529370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 530370007Sdonner 531370007Sdonner /* unknown unicast 2 from link0 */ 532370007Sdonner ng_counter_clear(r); 533370007Sdonner msg4.eh.ether_shost[5] = 0; 534370007Sdonner msg4.eh.ether_dhost[5] = 2; 535370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 536370007Sdonner ng_handle_events(50, &r); 537370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 538370007Sdonner 539370007Sdonner /* known unicast 0 from uplink2 */ 540370007Sdonner ng_counter_clear(r); 541370007Sdonner msg4.eh.ether_shost[5] = 2; 542370007Sdonner msg4.eh.ether_dhost[5] = 0; 543370007Sdonner ng_send_data("u2", &msg4, sizeof(msg4)); 544370007Sdonner ng_handle_events(50, &r); 545370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); 546370007Sdonner 547370007Sdonner /* known unicast 0 from link3 */ 548370007Sdonner ng_counter_clear(r); 549370007Sdonner msg4.eh.ether_shost[5] = 3; 550370007Sdonner msg4.eh.ether_dhost[5] = 0; 551370007Sdonner ng_send_data("l3", &msg4, sizeof(msg4)); 552370007Sdonner ng_handle_events(50, &r); 553370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); 554370007Sdonner 555370007Sdonner /* (un)known unicast 2 from uplink1 */ 556370007Sdonner ng_counter_clear(r); 557370007Sdonner msg4.eh.ether_shost[5] = 1; 558370007Sdonner msg4.eh.ether_dhost[5] = 2; 559370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 560370007Sdonner ng_handle_events(50, &r); 561370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 562370007Sdonner 563370007Sdonner /* (un)known unicast 2 from link0 */ 564370007Sdonner ng_counter_clear(r); 565370007Sdonner msg4.eh.ether_shost[5] = 0; 566370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 567370007Sdonner ng_handle_events(50, &r); 568370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 569370007Sdonner 570370007Sdonner /* unknown multicast 2 from uplink1 */ 571370007Sdonner ng_counter_clear(r); 572370007Sdonner msg4.eh.ether_shost[5] = 1; 573370007Sdonner msg4.eh.ether_dhost[0] = 0xff; 574370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 575370007Sdonner ng_handle_events(50, &r); 576370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 577370007Sdonner 578370007Sdonner /* unknown multicast 2 from link0 */ 579370007Sdonner ng_counter_clear(r); 580370007Sdonner msg4.eh.ether_shost[5] = 0; 581370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 582370007Sdonner ng_handle_events(50, &r); 583370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 584370007Sdonner 585370007Sdonner /* broadcast from uplink1 */ 586370007Sdonner ng_counter_clear(r); 587370007Sdonner msg4.eh.ether_shost[5] = 1; 588370007Sdonner memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); 589370007Sdonner ng_send_data("u1", &msg4, sizeof(msg4)); 590370007Sdonner ng_handle_events(50, &r); 591370007Sdonner ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); 592370007Sdonner 593370007Sdonner /* broadcast from link0 */ 594370007Sdonner ng_counter_clear(r); 595370007Sdonner msg4.eh.ether_shost[5] = 0; 596370007Sdonner ng_send_data("l0", &msg4, sizeof(msg4)); 597370007Sdonner ng_handle_events(50, &r); 598370007Sdonner ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); 599370007Sdonner 600370007Sdonner /* inspect mac table */ 601370007Sdonner ng_register_msg(get_tablesize); 602370007Sdonner rm.tok = ng_send_msg("bridge:", "gettable"); 603370007Sdonner rm.cnt = 0; 604370007Sdonner ng_handle_events(50, &rm); 605370007Sdonner ATF_CHECK(rm.cnt == 2); 606370007Sdonner 607370007Sdonner ng_shutdown("bridge:"); 608370007Sdonner} 609370007Sdonner 610370007SdonnerATF_TP_ADD_TCS(bridge) 611370007Sdonner{ 612370007Sdonner ATF_TP_ADD_TC(bridge, basic); 613370007Sdonner ATF_TP_ADD_TC(bridge, loop); 614370007Sdonner ATF_TP_ADD_TC(bridge, persistence); 615370007Sdonner ATF_TP_ADD_TC(bridge, many_unicasts); 616370007Sdonner ATF_TP_ADD_TC(bridge, many_broadcasts); 617370007Sdonner ATF_TP_ADD_TC(bridge, uplink_private); 618370007Sdonner ATF_TP_ADD_TC(bridge, uplink_classic); 619370007Sdonner 620370007Sdonner return atf_no_error(); 621370007Sdonner} 622370007Sdonner 623370007Sdonnerstatic void 624370007Sdonnerget_tablesize(char const *source, struct ng_mesg *msg, void *ctx) 625370007Sdonner{ 626370007Sdonner struct gettable *rm = ctx; 627370007Sdonner struct ng_bridge_host_ary *gt = (void *)msg->data; 628370007Sdonner 629370007Sdonner fprintf(stderr, "Response from %s to query %d\n", source, msg->header.token); 630370007Sdonner if (rm->tok == msg->header.token) 631370007Sdonner rm->cnt = gt->numHosts; 632370007Sdonner} 633