1
- /* $OpenBSD: ip_output.c,v 1.358 2020/12/20 21:15:47 bluhm Exp $ */
1
+ /* $OpenBSD: ip_output.c,v 1.359 2021/01/07 14:51:46 claudio Exp $ */
2
2
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
3
3
4
4
/*
73
73
#endif /* IPSEC */
74
74
75
75
int ip_pcbopts (struct mbuf * * , struct mbuf * );
76
+ int ip_multicast_if (struct ip_mreqn * , u_int , unsigned int * );
76
77
int ip_setmoptions (int , struct ip_moptions * * , struct mbuf * , u_int );
77
78
void ip_mloopback (struct ifnet * , struct mbuf * , struct sockaddr_in * );
78
79
static __inline u_int16_t __attribute__((__unused__ ))
@@ -1336,6 +1337,51 @@ ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m)
1336
1337
return (0 );
1337
1338
}
1338
1339
1340
+ /*
1341
+ * Lookup the interface based on the information in the ip_mreqn struct.
1342
+ */
1343
+ int
1344
+ ip_multicast_if (struct ip_mreqn * mreq , u_int rtableid , unsigned int * ifidx )
1345
+ {
1346
+ struct sockaddr_in sin ;
1347
+ struct rtentry * rt ;
1348
+
1349
+ /*
1350
+ * In case userland provides the imr_ifindex use this as interface.
1351
+ * If no interface address was provided, use the interface of
1352
+ * the route to the given multicast address.
1353
+ */
1354
+ if (mreq -> imr_ifindex != 0 ) {
1355
+ * ifidx = mreq -> imr_ifindex ;
1356
+ } else if (mreq -> imr_address .s_addr == INADDR_ANY ) {
1357
+ memset (& sin , 0 , sizeof (sin ));
1358
+ sin .sin_len = sizeof (sin );
1359
+ sin .sin_family = AF_INET ;
1360
+ sin .sin_addr = mreq -> imr_multiaddr ;
1361
+ rt = rtalloc (sintosa (& sin ), RT_RESOLVE , rtableid );
1362
+ if (!rtisvalid (rt )) {
1363
+ rtfree (rt );
1364
+ return EADDRNOTAVAIL ;
1365
+ }
1366
+ * ifidx = rt -> rt_ifidx ;
1367
+ rtfree (rt );
1368
+ } else {
1369
+ memset (& sin , 0 , sizeof (sin ));
1370
+ sin .sin_len = sizeof (sin );
1371
+ sin .sin_family = AF_INET ;
1372
+ sin .sin_addr = mreq -> imr_address ;
1373
+ rt = rtalloc (sintosa (& sin ), 0 , rtableid );
1374
+ if (!rtisvalid (rt ) || !ISSET (rt -> rt_flags , RTF_LOCAL )) {
1375
+ rtfree (rt );
1376
+ return EADDRNOTAVAIL ;
1377
+ }
1378
+ * ifidx = rt -> rt_ifidx ;
1379
+ rtfree (rt );
1380
+ }
1381
+
1382
+ return 0 ;
1383
+ }
1384
+
1339
1385
/*
1340
1386
* Set the IP multicast options in response to user setsockopt().
1341
1387
*/
@@ -1345,12 +1391,12 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
1345
1391
{
1346
1392
struct in_addr addr ;
1347
1393
struct in_ifaddr * ia ;
1348
- struct ip_mreq * mreq ;
1394
+ struct ip_mreqn mreqn ;
1349
1395
struct ifnet * ifp = NULL ;
1350
1396
struct ip_moptions * imo = * imop ;
1351
1397
struct in_multi * * immp ;
1352
- struct rtentry * rt ;
1353
1398
struct sockaddr_in sin ;
1399
+ unsigned int ifidx ;
1354
1400
int i , error = 0 ;
1355
1401
u_char loop ;
1356
1402
@@ -1438,63 +1484,41 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
1438
1484
* Add a multicast group membership.
1439
1485
* Group must be a valid IP multicast address.
1440
1486
*/
1441
- if (m == NULL || m -> m_len != sizeof (struct ip_mreq )) {
1487
+ if (m == NULL || !(m -> m_len == sizeof (struct ip_mreq ) ||
1488
+ m -> m_len == sizeof (struct ip_mreqn ))) {
1442
1489
error = EINVAL ;
1443
1490
break ;
1444
1491
}
1445
- mreq = mtod (m , struct ip_mreq * );
1446
- if (!IN_MULTICAST (mreq -> imr_multiaddr .s_addr )) {
1492
+ memset (& mreqn , 0 , sizeof (mreqn ));
1493
+ memcpy (& mreqn , mtod (m , void * ), m -> m_len );
1494
+ if (!IN_MULTICAST (mreqn .imr_multiaddr .s_addr )) {
1447
1495
error = EINVAL ;
1448
1496
break ;
1449
1497
}
1450
- /*
1451
- * If no interface address was provided, use the interface of
1452
- * the route to the given multicast address.
1453
- */
1454
- if (mreq -> imr_interface .s_addr == INADDR_ANY ) {
1455
- memset (& sin , 0 , sizeof (sin ));
1456
- sin .sin_len = sizeof (sin );
1457
- sin .sin_family = AF_INET ;
1458
- sin .sin_addr = mreq -> imr_multiaddr ;
1459
- rt = rtalloc (sintosa (& sin ), RT_RESOLVE , rtableid );
1460
- if (!rtisvalid (rt )) {
1461
- rtfree (rt );
1462
- error = EADDRNOTAVAIL ;
1463
- break ;
1464
- }
1465
- } else {
1466
- memset (& sin , 0 , sizeof (sin ));
1467
- sin .sin_len = sizeof (sin );
1468
- sin .sin_family = AF_INET ;
1469
- sin .sin_addr = mreq -> imr_interface ;
1470
- rt = rtalloc (sintosa (& sin ), 0 , rtableid );
1471
- if (!rtisvalid (rt ) || !ISSET (rt -> rt_flags , RTF_LOCAL )) {
1472
- rtfree (rt );
1473
- error = EADDRNOTAVAIL ;
1474
- break ;
1475
- }
1476
- }
1477
- ifp = if_get (rt -> rt_ifidx );
1478
- rtfree (rt );
1498
+
1499
+ error = ip_multicast_if (& mreqn , rtableid , & ifidx );
1500
+ if (error )
1501
+ break ;
1479
1502
1480
1503
/*
1481
1504
* See if we found an interface, and confirm that it
1482
1505
* supports multicast.
1483
1506
*/
1507
+ ifp = if_get (ifidx );
1484
1508
if (ifp == NULL || (ifp -> if_flags & IFF_MULTICAST ) == 0 ) {
1485
1509
error = EADDRNOTAVAIL ;
1486
1510
if_put (ifp );
1487
1511
break ;
1488
1512
}
1513
+
1489
1514
/*
1490
1515
* See if the membership already exists or if all the
1491
1516
* membership slots are full.
1492
1517
*/
1493
1518
for (i = 0 ; i < imo -> imo_num_memberships ; ++ i ) {
1494
- if (imo -> imo_membership [i ]-> inm_ifidx
1495
- == ifp -> if_index &&
1519
+ if (imo -> imo_membership [i ]-> inm_ifidx == ifidx &&
1496
1520
imo -> imo_membership [i ]-> inm_addr .s_addr
1497
- == mreq -> imr_multiaddr .s_addr )
1521
+ == mreqn . imr_multiaddr .s_addr )
1498
1522
break ;
1499
1523
}
1500
1524
if (i < imo -> imo_num_memberships ) {
@@ -1506,9 +1530,10 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
1506
1530
struct in_multi * * nmships , * * omships ;
1507
1531
size_t newmax ;
1508
1532
/*
1509
- * Resize the vector to next power-of-two minus 1. If the
1510
- * size would exceed the maximum then we know we've really
1511
- * run out of entries. Otherwise, we reallocate the vector.
1533
+ * Resize the vector to next power-of-two minus 1. If
1534
+ * the size would exceed the maximum then we know we've
1535
+ * really run out of entries. Otherwise, we reallocate
1536
+ * the vector.
1512
1537
*/
1513
1538
nmships = NULL ;
1514
1539
omships = imo -> imo_membership ;
@@ -1538,7 +1563,7 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
1538
1563
* address list for the given interface.
1539
1564
*/
1540
1565
if ((imo -> imo_membership [i ] =
1541
- in_addmulti (& mreq -> imr_multiaddr , ifp )) == NULL ) {
1566
+ in_addmulti (& mreqn . imr_multiaddr , ifp )) == NULL ) {
1542
1567
error = ENOBUFS ;
1543
1568
if_put (ifp );
1544
1569
break ;
@@ -1552,42 +1577,34 @@ ip_setmoptions(int optname, struct ip_moptions **imop, struct mbuf *m,
1552
1577
* Drop a multicast group membership.
1553
1578
* Group must be a valid IP multicast address.
1554
1579
*/
1555
- if (m == NULL || m -> m_len != sizeof (struct ip_mreq )) {
1580
+ if (m == NULL || !(m -> m_len == sizeof (struct ip_mreq ) ||
1581
+ m -> m_len == sizeof (struct ip_mreqn ))) {
1556
1582
error = EINVAL ;
1557
1583
break ;
1558
1584
}
1559
- mreq = mtod (m , struct ip_mreq * );
1560
- if (!IN_MULTICAST (mreq -> imr_multiaddr .s_addr )) {
1585
+ memset (& mreqn , 0 , sizeof (mreqn ));
1586
+ memcpy (& mreqn , mtod (m , void * ), m -> m_len );
1587
+ if (!IN_MULTICAST (mreqn .imr_multiaddr .s_addr )) {
1561
1588
error = EINVAL ;
1562
1589
break ;
1563
1590
}
1591
+
1564
1592
/*
1565
1593
* If an interface address was specified, get a pointer
1566
1594
* to its ifnet structure.
1567
1595
*/
1568
- if (mreq -> imr_interface .s_addr == INADDR_ANY )
1569
- ifp = NULL ;
1570
- else {
1571
- memset (& sin , 0 , sizeof (sin ));
1572
- sin .sin_len = sizeof (sin );
1573
- sin .sin_family = AF_INET ;
1574
- sin .sin_addr = mreq -> imr_interface ;
1575
- ia = ifatoia (ifa_ifwithaddr (sintosa (& sin ), rtableid ));
1576
- if (ia == NULL ) {
1577
- error = EADDRNOTAVAIL ;
1578
- break ;
1579
- }
1580
- ifp = ia -> ia_ifp ;
1581
- }
1596
+ error = ip_multicast_if (& mreqn , rtableid , & ifidx );
1597
+ if (error )
1598
+ break ;
1599
+
1582
1600
/*
1583
1601
* Find the membership in the membership array.
1584
1602
*/
1585
1603
for (i = 0 ; i < imo -> imo_num_memberships ; ++ i ) {
1586
- if ((ifp == NULL ||
1587
- imo -> imo_membership [i ]-> inm_ifidx ==
1588
- ifp -> if_index ) &&
1604
+ if ((ifidx == 0 ||
1605
+ imo -> imo_membership [i ]-> inm_ifidx == ifidx ) &&
1589
1606
imo -> imo_membership [i ]-> inm_addr .s_addr ==
1590
- mreq -> imr_multiaddr .s_addr )
1607
+ mreqn . imr_multiaddr .s_addr )
1591
1608
break ;
1592
1609
}
1593
1610
if (i == imo -> imo_num_memberships ) {
0 commit comments