3 Copyright (C) 2008 Everton da Silva Marques
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
32 #include "pim_mroute.h"
36 #include "pim_iface.h"
37 #include "pim_macro.h"
40 #include "pim_register.h"
41 #include "pim_ifchannel.h"
42 #include "pim_zlookup.h"
45 extern struct zebra_privs_t pimd_privs
;
47 static void mroute_read_on(void);
49 static int pim_mroute_set(int fd
, int enable
)
52 int opt
= enable
? MRT_INIT
: MRT_DONE
;
53 socklen_t opt_len
= sizeof(opt
);
55 err
= setsockopt(fd
, IPPROTO_IP
, opt
, &opt
, opt_len
);
57 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s",
58 __FILE__
, __PRETTY_FUNCTION__
,
59 fd
, enable
? "MRT_INIT" : "MRT_DONE", opt
, errno
, safe_strerror(errno
));
65 int upcalls
= IGMPMSG_WRVIFWHOLE
;
68 err
= setsockopt (fd
, IPPROTO_IP
, opt
, &upcalls
, sizeof (upcalls
));
71 zlog_warn ("Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
72 errno
, safe_strerror (errno
));
80 static const char *igmpmsgtype2str
[IGMPMSG_WRVIFWHOLE
+ 1] = {
88 pim_mroute_msg_nocache (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
90 struct pim_interface
*pim_ifp
= ifp
->info
;
91 struct pim_upstream
*up
;
94 struct channel_oil
*oil
;
96 rpg
= RP(msg
->im_dst
);
98 * If the incoming interface is unknown OR
99 * the Interface type is SSM we don't need to
102 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
104 (!(PIM_I_am_DR(pim_ifp
))) ||
105 (pim_ifp
->itype
== PIM_INTERFACE_SSM
))
109 * If we've received a multicast packet that isn't connected to
112 if (!pim_if_connected_to_source (ifp
, msg
->im_src
))
114 if (PIM_DEBUG_MROUTE_DETAIL
)
115 zlog_debug ("%s: Received incoming packet that doesn't originate on our seg",
116 __PRETTY_FUNCTION__
);
120 memset (&sg
, 0, sizeof (struct prefix_sg
));
121 sg
.src
= msg
->im_src
;
122 sg
.grp
= msg
->im_dst
;
124 if (PIM_DEBUG_MROUTE
) {
125 zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
126 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
129 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
131 if (PIM_DEBUG_MROUTE
) {
132 zlog_debug("%s: Failure to add channel oil for %s",
134 pim_str_sg_dump (&sg
));
139 up
= pim_upstream_add (&sg
, ifp
);
141 if (PIM_DEBUG_MROUTE
) {
142 zlog_debug("%s: Failure to add upstream information for %s",
144 pim_str_sg_dump (&sg
));
148 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
150 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
152 up
->channel_oil
= oil
;
153 up
->channel_oil
->cc
.pktcnt
++;
154 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
155 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
156 up
->join_state
= PIM_UPSTREAM_JOINED
;
162 pim_mroute_msg_wholepkt (int fd
, struct interface
*ifp
, const char *buf
)
164 struct pim_interface
*pim_ifp
;
167 const struct ip
*ip_hdr
;
168 struct pim_upstream
*up
;
170 ip_hdr
= (const struct ip
*)buf
;
172 memset (&sg
, 0, sizeof (struct prefix_sg
));
173 sg
.src
= ip_hdr
->ip_src
;
174 sg
.grp
= ip_hdr
->ip_dst
;
176 up
= pim_upstream_find(&sg
);
178 if (PIM_DEBUG_MROUTE_DETAIL
) {
179 zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
180 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
185 pim_ifp
= up
->rpf
.source_nexthop
.interface
->info
;
189 if ((pim_rpf_addr_is_inaddr_none (rpg
)) ||
191 (!(PIM_I_am_DR(pim_ifp
))) ||
192 (pim_ifp
->itype
== PIM_INTERFACE_SSM
)) {
193 if (PIM_DEBUG_MROUTE
) {
194 zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__
);
200 * If we've received a register suppress
203 pim_register_send((uint8_t *)buf
+ sizeof(struct ip
), ntohs (ip_hdr
->ip_len
),
204 pim_ifp
->primary_address
, rpg
, 0);
210 pim_mroute_msg_wrongvif (int fd
, struct interface
*ifp
, const struct igmpmsg
*msg
)
212 struct pim_ifchannel
*ch
;
213 struct pim_interface
*pim_ifp
;
216 memset (&sg
, 0, sizeof (struct prefix_sg
));
217 sg
.src
= msg
->im_src
;
218 sg
.grp
= msg
->im_dst
;
221 Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
223 RFC 4601 4.8.2. PIM-SSM-Only Routers
225 iif is the incoming interface of the packet.
226 if (iif is in inherited_olist(S,G)) {
227 send Assert(S,G) on iif
232 if (PIM_DEBUG_MROUTE
) {
233 zlog_debug("%s: WRONGVIF (S,G)=%s could not find input interface for input_vif_index=%d",
235 pim_str_sg_dump (&sg
), msg
->im_vif
);
242 if (PIM_DEBUG_MROUTE
) {
243 zlog_debug("%s: WRONGVIF (S,G)=%s multicast not enabled on interface %s",
245 pim_str_sg_dump (&sg
), ifp
->name
);
250 ch
= pim_ifchannel_find(ifp
, &sg
);
252 if (PIM_DEBUG_MROUTE
) {
253 zlog_debug("%s: WRONGVIF (S,G)=%s could not find channel on interface %s",
255 pim_str_sg_dump (&sg
), ifp
->name
);
261 RFC 4601: 4.6.1. (S,G) Assert Message State Machine
263 Transitions from NoInfo State
265 An (S,G) data packet arrives on interface I, AND
266 CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
267 downstream interface that is in our (S,G) outgoing interface
268 list. We optimistically assume that we will be the assert
269 winner for this (S,G), and so we transition to the "I am Assert
270 Winner" state and perform Actions A1 (below), which will
271 initiate the assert negotiation for (S,G).
274 if (ch
->ifassert_state
!= PIM_IFASSERT_NOINFO
) {
275 if (PIM_DEBUG_MROUTE
) {
276 zlog_debug("%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
278 pim_str_sg_dump (&sg
), ifp
->name
);
283 if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch
->flags
)) {
284 if (PIM_DEBUG_MROUTE
) {
285 zlog_debug("%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
287 pim_str_sg_dump (&sg
), ifp
->name
);
292 if (assert_action_a1(ch
)) {
293 if (PIM_DEBUG_MROUTE
) {
294 zlog_debug("%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
296 pim_str_sg_dump (&sg
), ifp
->name
);
305 pim_mroute_msg_wrvifwhole (int fd
, struct interface
*ifp
, const char *buf
)
307 const struct ip
*ip_hdr
= (const struct ip
*)buf
;
308 struct pim_interface
*pim_ifp
;
309 struct pim_ifchannel
*ch
;
310 struct pim_upstream
*up
;
312 struct channel_oil
*oil
;
314 memset (&sg
, 0, sizeof (struct prefix_sg
));
315 sg
.src
= ip_hdr
->ip_src
;
316 sg
.grp
= ip_hdr
->ip_dst
;
318 if (PIM_DEBUG_MROUTE
)
319 zlog_debug ("Received WHOLEPKT Wrong Vif for %s on %s",
320 pim_str_sg_dump (&sg
), ifp
->name
);
322 ch
= pim_ifchannel_find(ifp
, &sg
);
325 if (PIM_DEBUG_MROUTE
)
326 zlog_debug ("WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
327 pim_str_sg_dump (&sg
), ifp
->name
);
331 if (PIM_DEBUG_MROUTE
)
332 zlog_debug ("If channel: %p", ch
);
334 up
= pim_upstream_find (&sg
);
338 * If we are the fhr that means we are getting a callback during
339 * the pimreg period, so I believe we can ignore this packet
341 if (!PIM_UPSTREAM_FLAG_TEST_FHR(up
->flags
))
343 struct pim_nexthop source
;
344 struct pim_rpf
*rpf
= RP (sg
.grp
);
345 pim_ifp
= rpf
->source_nexthop
.interface
->info
;
347 //No if channel, but upstream we are at the RP.
348 pim_nexthop_lookup (&source
, up
->upstream_register
);
349 pim_register_stop_send(source
.interface
, &sg
, pim_ifp
->primary_address
, up
->upstream_register
);
350 if (!up
->channel_oil
)
351 up
->channel_oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
352 if (!up
->channel_oil
->installed
)
353 pim_mroute_add (up
->channel_oil
);
354 //Send S bit down the join.
355 up
->sptbit
= PIM_UPSTREAM_SPTBIT_TRUE
;
361 oil
= pim_channel_oil_add (&sg
, pim_ifp
->mroute_vif_index
);
363 pim_mroute_add (oil
);
364 if (pim_if_connected_to_source (ifp
, sg
.src
))
366 up
= pim_upstream_add (&sg
, ifp
);
369 if (PIM_DEBUG_MROUTE
)
370 zlog_debug ("%s: WRONGVIF%s unable to create upstream on interface",
371 pim_str_sg_dump (&sg
), ifp
->name
);
374 PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up
->flags
);
375 PIM_UPSTREAM_FLAG_SET_FHR(up
->flags
);
377 pim_upstream_keep_alive_timer_start (up
, qpim_keep_alive_time
);
378 up
->channel_oil
= oil
;
379 up
->channel_oil
->cc
.pktcnt
++;
380 pim_channel_add_oif (up
->channel_oil
, pim_regiface
, PIM_OIF_FLAG_PROTO_PIM
);
381 up
->join_state
= PIM_UPSTREAM_JOINED
;
382 pim_upstream_inherited_olist (up
);
384 // Send the packet to the RP
385 pim_mroute_msg_wholepkt (fd
, ifp
, buf
);
391 int pim_mroute_msg(int fd
, const char *buf
, int buf_size
)
393 struct interface
*ifp
;
394 const struct ip
*ip_hdr
;
395 const struct igmpmsg
*msg
;
396 char src_str
[100] = "<src?>";
397 char grp_str
[100] = "<grp?>";
399 ip_hdr
= (const struct ip
*) buf
;
401 /* kernel upcall must have protocol=0 */
403 /* this is not a kernel upcall */
404 if (PIM_DEBUG_MROUTE_DETAIL
) {
405 pim_inet4_dump("<src?>", ip_hdr
->ip_src
, src_str
, sizeof(src_str
));
406 pim_inet4_dump("<grp?>", ip_hdr
->ip_dst
, grp_str
, sizeof(grp_str
));
407 zlog_debug("%s: not a kernel upcall proto=%d src: %s dst: %s msg_size=%d",
408 __PRETTY_FUNCTION__
, ip_hdr
->ip_p
, src_str
, grp_str
, buf_size
);
413 msg
= (const struct igmpmsg
*) buf
;
415 ifp
= pim_if_find_by_vif_index(msg
->im_vif
);
417 if (PIM_DEBUG_MROUTE
) {
418 pim_inet4_dump("<src?>", msg
->im_src
, src_str
, sizeof(src_str
));
419 pim_inet4_dump("<grp?>", msg
->im_dst
, grp_str
, sizeof(grp_str
));
420 zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d",
422 igmpmsgtype2str
[msg
->im_msgtype
],
432 switch (msg
->im_msgtype
) {
433 case IGMPMSG_WRONGVIF
:
434 return pim_mroute_msg_wrongvif(fd
, ifp
, msg
);
436 case IGMPMSG_NOCACHE
:
437 return pim_mroute_msg_nocache(fd
, ifp
, msg
);
439 case IGMPMSG_WHOLEPKT
:
440 return pim_mroute_msg_wholepkt(fd
, ifp
, (const char *)msg
);
442 case IGMPMSG_WRVIFWHOLE
:
443 return pim_mroute_msg_wrvifwhole (fd
, ifp
, (const char *)msg
);
452 static int mroute_read_msg(int fd
)
457 rd
= read(fd
, buf
, sizeof(buf
));
459 zlog_warn("%s: failure reading fd=%d: errno=%d: %s",
460 __PRETTY_FUNCTION__
, fd
, errno
, safe_strerror(errno
));
464 return pim_mroute_msg(fd
, buf
, rd
);
467 static int mroute_read(struct thread
*t
)
473 zassert(!THREAD_ARG(t
));
476 zassert(fd
== qpim_mroute_socket_fd
);
478 result
= mroute_read_msg(fd
);
481 qpim_mroute_socket_reader
= 0;
487 static void mroute_read_on()
489 zassert(!qpim_mroute_socket_reader
);
490 zassert(PIM_MROUTE_IS_ENABLED
);
492 THREAD_READ_ON(master
, qpim_mroute_socket_reader
,
493 mroute_read
, 0, qpim_mroute_socket_fd
);
496 static void mroute_read_off()
498 THREAD_OFF(qpim_mroute_socket_reader
);
501 int pim_mroute_socket_enable()
505 if (PIM_MROUTE_IS_ENABLED
)
508 if ( pimd_privs
.change (ZPRIVS_RAISE
) )
509 zlog_err ("pim_mroute_socket_enable: could not raise privs, %s",
510 safe_strerror (errno
) );
512 fd
= socket(AF_INET
, SOCK_RAW
, IPPROTO_IGMP
);
514 if ( pimd_privs
.change (ZPRIVS_LOWER
) )
515 zlog_err ("pim_mroute_socket_enable: could not lower privs, %s",
516 safe_strerror (errno
) );
519 zlog_warn("Could not create mroute socket: errno=%d: %s",
520 errno
, safe_strerror(errno
));
524 if (pim_mroute_set(fd
, 1)) {
525 zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s",
526 fd
, errno
, safe_strerror(errno
));
531 qpim_mroute_socket_fd
= fd
;
533 qpim_mroute_socket_creation
= pim_time_monotonic_sec();
539 int pim_mroute_socket_disable()
541 if (PIM_MROUTE_IS_DISABLED
)
544 if (pim_mroute_set(qpim_mroute_socket_fd
, 0)) {
545 zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s",
546 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
550 if (close(qpim_mroute_socket_fd
)) {
551 zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
552 qpim_mroute_socket_fd
, errno
, safe_strerror(errno
));
557 qpim_mroute_socket_fd
= -1;
563 For each network interface (e.g., physical or a virtual tunnel) that
564 would be used for multicast forwarding, a corresponding multicast
565 interface must be added to the kernel.
567 int pim_mroute_add_vif(struct interface
*ifp
, struct in_addr ifaddr
, unsigned char flags
)
569 struct pim_interface
*pim_ifp
= ifp
->info
;
573 if (PIM_MROUTE_IS_DISABLED
) {
574 zlog_warn("%s: global multicast is disabled",
575 __PRETTY_FUNCTION__
);
579 memset(&vc
, 0, sizeof(vc
));
580 vc
.vifc_vifi
= pim_ifp
->mroute_vif_index
;
581 #ifdef VIFF_USE_IFINDEX
582 vc
.vifc_lcl_ifindex
= ifp
->ifindex
;
584 if (ifaddr
.s_addr
== INADDR_ANY
) {
585 zlog_warn("%s: unnumbered interfaces are not supported on this platform",
586 __PRETTY_FUNCTION__
);
589 memcpy(&vc
.vifc_lcl_addr
, &ifaddr
, sizeof(vc
.vifc_lcl_addr
));
591 vc
.vifc_flags
= flags
;
592 vc
.vifc_threshold
= PIM_MROUTE_MIN_TTL
;
593 vc
.vifc_rate_limit
= 0;
595 #ifdef PIM_DVMRP_TUNNEL
596 if (vc
.vifc_flags
& VIFF_TUNNEL
) {
597 memcpy(&vc
.vifc_rmt_addr
, &vif_remote_addr
, sizeof(vc
.vifc_rmt_addr
));
601 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_VIF
, (void*) &vc
, sizeof(vc
));
603 char ifaddr_str
[100];
605 pim_inet4_dump("<ifaddr?>", ifaddr
, ifaddr_str
, sizeof(ifaddr_str
));
607 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s,flag=%d): errno=%d: %s",
608 __FILE__
, __PRETTY_FUNCTION__
,
609 qpim_mroute_socket_fd
, ifp
->ifindex
, ifaddr_str
, flags
,
610 errno
, safe_strerror(errno
));
617 int pim_mroute_del_vif(int vif_index
)
622 if (PIM_MROUTE_IS_DISABLED
) {
623 zlog_warn("%s: global multicast is disabled",
624 __PRETTY_FUNCTION__
);
628 memset(&vc
, 0, sizeof(vc
));
629 vc
.vifc_vifi
= vif_index
;
631 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_VIF
, (void*) &vc
, sizeof(vc
));
633 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
634 __FILE__
, __PRETTY_FUNCTION__
,
635 qpim_mroute_socket_fd
, vif_index
,
636 errno
, safe_strerror(errno
));
643 int pim_mroute_add(struct channel_oil
*c_oil
)
647 int orig_iif_vif
= 0;
649 qpim_mroute_add_last
= pim_time_monotonic_sec();
650 ++qpim_mroute_add_events
;
652 if (PIM_MROUTE_IS_DISABLED
) {
653 zlog_warn("%s: global multicast is disabled",
654 __PRETTY_FUNCTION__
);
658 /* The linux kernel *expects* the incoming
659 * vif to be part of the outgoing list
660 * in the case of a (*,G).
662 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
664 orig
= c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
];
665 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = 1;
669 * If we have an unresolved cache entry for the S,G
670 * it is owned by the pimreg for the incoming IIF
671 * So set pimreg as the IIF temporarily to cause
672 * the packets to be forwarded. Then set it
673 * to the correct IIF afterwords.
675 if (!c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
676 c_oil
->oil
.mfcc_parent
!= 0)
678 orig_iif_vif
= c_oil
->oil
.mfcc_parent
;
679 c_oil
->oil
.mfcc_parent
= 0;
681 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
682 &c_oil
->oil
, sizeof(c_oil
->oil
));
684 if (!err
&& !c_oil
->installed
&& c_oil
->oil
.mfcc_origin
.s_addr
!= INADDR_ANY
&&
687 c_oil
->oil
.mfcc_parent
= orig_iif_vif
;
688 err
= setsockopt (qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_ADD_MFC
,
689 &c_oil
->oil
, sizeof (c_oil
->oil
));
692 if (c_oil
->oil
.mfcc_origin
.s_addr
== INADDR_ANY
)
693 c_oil
->oil
.mfcc_ttls
[c_oil
->oil
.mfcc_parent
] = orig
;
696 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s",
697 __FILE__
, __PRETTY_FUNCTION__
,
698 qpim_mroute_socket_fd
,
699 errno
, safe_strerror(errno
));
703 c_oil
->installed
= 1;
707 int pim_mroute_del (struct channel_oil
*c_oil
)
711 qpim_mroute_del_last
= pim_time_monotonic_sec();
712 ++qpim_mroute_del_events
;
714 if (PIM_MROUTE_IS_DISABLED
) {
715 zlog_warn("%s: global multicast is disabled",
716 __PRETTY_FUNCTION__
);
720 err
= setsockopt(qpim_mroute_socket_fd
, IPPROTO_IP
, MRT_DEL_MFC
, &c_oil
->oil
, sizeof(c_oil
->oil
));
722 zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s",
723 __FILE__
, __PRETTY_FUNCTION__
,
724 qpim_mroute_socket_fd
,
725 errno
, safe_strerror(errno
));
729 c_oil
->installed
= 0;
735 pim_mroute_update_counters (struct channel_oil
*c_oil
)
737 struct sioc_sg_req sgreq
;
739 memset (&sgreq
, 0, sizeof(sgreq
));
740 sgreq
.src
= c_oil
->oil
.mfcc_origin
;
741 sgreq
.grp
= c_oil
->oil
.mfcc_mcastgrp
;
743 c_oil
->cc
.oldpktcnt
= c_oil
->cc
.pktcnt
;
744 c_oil
->cc
.oldbytecnt
= c_oil
->cc
.bytecnt
;
745 c_oil
->cc
.oldwrong_if
= c_oil
->cc
.wrong_if
;
746 c_oil
->cc
.oldlastused
= c_oil
->cc
.lastused
;
748 pim_zlookup_sg_statistics (c_oil
);
749 if (ioctl (qpim_mroute_socket_fd
, SIOCGETSGCNT
, &sgreq
))
752 char source_str
[100];
754 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
755 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
757 zlog_warn ("ioctl(SIOCGETSGCNT=%lu) failure for (S,G)=(%s,%s): errno=%d: %s",
758 (unsigned long)SIOCGETSGCNT
,
762 safe_strerror(errno
));
766 c_oil
->cc
.pktcnt
= sgreq
.pktcnt
;
767 c_oil
->cc
.bytecnt
= sgreq
.bytecnt
;
768 c_oil
->cc
.wrong_if
= sgreq
.wrong_if
;