1 /*
2  * scamper_dl: manage BPF/PF_PACKET datalink instances for scamper
3  *
4  * $Id: scamper_dl.c,v 1.187 2020/03/17 07:32:16 mjl Exp $
5  *
6  *          Matthew Luckie
7  *          Ben Stasiewicz added fragmentation support.
8  *          Stephen Eichler added SACK support.
9  *
10  *          Supported by:
11  *           The University of Waikato
12  *           NLANR Measurement and Network Analysis
13  *           CAIDA
14  *           The WIDE Project
15  *
16  * Copyright (C) 2004-2006 Matthew Luckie
17  * Copyright (C) 2006-2011 The University of Waikato
18  * Copyright (C) 2012      Matthew Luckie
19  * Copyright (C) 2014-2015 The Regents of the University of California
20  *
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License as published by
23  * the Free Software Foundation, version 2.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
33  *
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 #include "internal.h"
40 
41 #if defined(HAVE_BPF) || defined(__linux__)
42 #define HAVE_BPF_FILTER
43 #endif
44 
45 #include "scamper.h"
46 #include "scamper_debug.h"
47 #include "scamper_addr.h"
48 #include "scamper_fds.h"
49 #include "scamper_dl.h"
50 #include "scamper_privsep.h"
51 #include "scamper_task.h"
52 #include "scamper_if.h"
53 #include "scamper_osinfo.h"
54 #include "utils.h"
55 
56 #if defined(HAVE_BPF) && defined(DLT_APPLE_IP_OVER_IEEE1394)
57 #define HAVE_FIREWIRE
58 #elif defined(__linux__) && defined(ARPHRD_IEEE1394)
59 #define HAVE_FIREWIRE
60 #endif
61 
62 struct scamper_dl
63 {
64   /* the file descriptor that scamper has on the datalink */
65   scamper_fd_t  *fdn;
66 
67   /* the callback used to read packets off the datalink */
68   int          (*dlt_cb)(scamper_dl_rec_t *dl, uint8_t *pkt, size_t len);
69 
70   /* the underlying type of the datalink (DLT_* or ARPHDR_* values) */
71   int            type;
72 
73   /* how the user should frame packet to transmit on the datalink */
74   int            tx_type;
75 
76   /* if we're using BPF, then we need to use an appropriately sized buffer */
77 #if defined(HAVE_BPF)
78   u_int          readbuf_len;
79 #endif
80 
81 };
82 
83 static uint8_t          *readbuf = NULL;
84 static size_t            readbuf_len = 0;
85 
86 #if defined(HAVE_BPF)
87 static const scamper_osinfo_t *osinfo = NULL;
88 #endif
89 
90 /*
91  * dl_parse_ip
92  *
93  * pkt points to the beginning of an IP header.  given the length of the
94  * packet, parse the contents into a datalink record structure.
95  */
96 static int dl_parse_ip(scamper_dl_rec_t *dl, uint8_t *pktbuf, size_t pktlen)
97 {
98   struct ip        *ip4;
99   struct ip6_hdr   *ip6;
100   struct ip6_ext   *ip6_exthdr;
101   struct ip6_frag  *ip6_fraghdr;
102   struct icmp      *icmp4;
103   struct icmp6_hdr *icmp6;
104   struct tcphdr    *tcp;
105   struct udphdr    *udp;
106   size_t            iplen;
107   size_t            extlen;
108   uint8_t          *pkt = pktbuf;
109   size_t            len = pktlen;
110   size_t            off;
111   uint8_t          *tmp;
112   uint16_t          u16;
113   int               i;
114 
115   if((pkt[0] >> 4) == 4) /* IPv4 */
116     {
117       ip4 = (struct ip *)pkt;
118 
119 #ifndef _WIN32
120       iplen = (ip4->ip_hl << 2);
121 #else
122       iplen = ((ip4->ip_vhl) & 0xf) << 2;
123 #endif
124 
125       /*
126        * make sure that the captured packet has enough to cover the whole
127        * of the IP header
128        */
129       if(iplen > len)
130 	return 0;
131 
132       /* figure out fragmentation details */
133       u16 = ntohs(ip4->ip_off);
134       dl->dl_ip_off = (u16 & IP_OFFMASK) * 8;
135       if(dl->dl_ip_off != 0 || (u16 & IP_MF) != 0)
136 	dl->dl_ip_flags |= SCAMPER_DL_IP_FLAG_FRAG;
137       if((u16 & IP_DF) != 0)
138 	dl->dl_ip_flags |= SCAMPER_DL_IP_FLAG_DF;
139       if((u16 & IP_MF) != 0)
140 	dl->dl_ip_flags |= SCAMPER_DL_IP_FLAG_MF;
141 
142       dl->dl_af       = AF_INET;
143       dl->dl_ip_hl    = iplen;
144       dl->dl_ip_proto = ip4->ip_p;
145       dl->dl_ip_size  = ntohs(ip4->ip_len);
146       dl->dl_ip_id    = ntohs(ip4->ip_id);
147       dl->dl_ip_tos   = ip4->ip_tos;
148       dl->dl_ip_ttl   = ip4->ip_ttl;
149       dl->dl_ip_src   = (uint8_t *)&ip4->ip_src;
150       dl->dl_ip_dst   = (uint8_t *)&ip4->ip_dst;
151 
152       dl->dl_flags   |= SCAMPER_DL_REC_FLAG_NET;
153       dl->dl_net_type = SCAMPER_DL_REC_NET_TYPE_IP;
154 
155       pkt += iplen;
156       len -= iplen;
157     }
158   else if((pkt[0] >> 4) == 6) /* IPv6 */
159     {
160       ip6 = (struct ip6_hdr *)pkt;
161 
162       if((iplen = sizeof(struct ip6_hdr)) > len)
163 	return 0;
164 
165       dl->dl_af       = AF_INET6;
166       dl->dl_ip_hl    = iplen;
167       dl->dl_ip_flow  = ntohl(ip6->ip6_flow) & 0xfffff;
168       dl->dl_ip_proto = ip6->ip6_nxt;
169       dl->dl_ip_size  = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
170       dl->dl_ip_hlim  = ip6->ip6_hlim;
171       dl->dl_ip_src   = (uint8_t *)&ip6->ip6_src;
172       dl->dl_ip_dst   = (uint8_t *)&ip6->ip6_dst;
173       dl->dl_flags   |= SCAMPER_DL_REC_FLAG_NET;
174       dl->dl_net_type = SCAMPER_DL_REC_NET_TYPE_IP;
175 
176       pkt += iplen;
177       len -= iplen;
178 
179       /* Process any IPv6 fragmentation headers */
180       for(;;)
181         {
182 	  switch(dl->dl_ip_proto)
183             {
184 	    case IPPROTO_HOPOPTS:
185 	    case IPPROTO_DSTOPTS:
186 	    case IPPROTO_ROUTING:
187 	      if(sizeof(struct ip6_ext) > len)
188 		return 0;
189 	      ip6_exthdr = (struct ip6_ext *)pkt;
190 	      if((extlen = (ip6_exthdr->ip6e_len * 8) + 8) > len)
191 		return 0;
192 	      dl->dl_ip_proto = ip6_exthdr->ip6e_nxt;
193 	      break;
194 
195 	    case IPPROTO_FRAGMENT:
196 	      if((extlen = sizeof(struct ip6_frag)) > len)
197 		return 0;
198 	      ip6_fraghdr = (struct ip6_frag *)pkt;
199 	      dl->dl_ip6_id = ntohl(ip6_fraghdr->ip6f_ident);
200 	      dl->dl_ip_off = ntohs(ip6_fraghdr->ip6f_offlg) & 0xfff8;
201 	      dl->dl_ip_proto = ip6_fraghdr->ip6f_nxt;
202 	      dl->dl_ip_flags |= SCAMPER_DL_IP_FLAG_FRAG;
203 	      if(ntohs(ip6_fraghdr->ip6f_offlg) & 0x1)
204 		dl->dl_ip_flags |= SCAMPER_DL_IP_FLAG_MF;
205 	      break;
206 
207 	    default:
208 	      extlen = 0;
209 	      break;
210             }
211 
212 	  if(extlen == 0)
213 	    break;
214 
215 	  dl->dl_ip_hl += extlen;
216 	  pkt += extlen;
217 	  len -= extlen;
218         }
219     }
220   else
221     {
222       return 0;
223     }
224 
225   dl->dl_ip_data    = pkt;
226   dl->dl_ip_datalen = len;
227 
228   /*
229    * can't do any further processing of the packet if we're seeing
230    * a later fragment
231    */
232   if(dl->dl_ip_off != 0)
233     return 1;
234 
235   if(dl->dl_ip_proto == IPPROTO_UDP)
236     {
237       if((int)sizeof(struct udphdr) > len)
238 	{
239 	  return 0;
240 	}
241 
242       udp = (struct udphdr *)pkt;
243       dl->dl_udp_dport = ntohs(udp->uh_dport);
244       dl->dl_udp_sport = ntohs(udp->uh_sport);
245       dl->dl_udp_sum   = udp->uh_sum;
246       dl->dl_flags    |= SCAMPER_DL_REC_FLAG_TRANS;
247     }
248   else if(dl->dl_ip_proto == IPPROTO_TCP)
249     {
250       if((int)sizeof(struct tcphdr) > len)
251 	{
252 	  return 0;
253 	}
254 
255       tcp = (struct tcphdr *)pkt;
256       dl->dl_tcp_dport  = ntohs(tcp->th_dport);
257       dl->dl_tcp_sport  = ntohs(tcp->th_sport);
258       dl->dl_tcp_seq    = ntohl(tcp->th_seq);
259       dl->dl_tcp_ack    = ntohl(tcp->th_ack);
260 #ifndef _WIN32
261       dl->dl_tcp_hl     = tcp->th_off * 4;
262 #else
263       dl->dl_tcp_hl     = (tcp->th_offx2 >> 4) * 4;
264 #endif
265       dl->dl_tcp_flags  = tcp->th_flags;
266       dl->dl_tcp_win    = ntohs(tcp->th_win);
267       dl->dl_flags     |= SCAMPER_DL_REC_FLAG_TRANS;
268 
269       if(dl->dl_tcp_hl >= 20 && len >= dl->dl_tcp_hl)
270 	{
271 	  off = 20;
272 	  while(off < dl->dl_tcp_hl)
273 	    {
274 	      tmp = pkt + off;
275 
276 	      if(tmp[0] == 0) /* End of option list */
277 		break;
278 
279 	      if(tmp[0] == 1) /* no-op */
280 		{
281 		  off++;
282 		  continue;
283 		}
284 
285 	      if(tmp[1] == 0)
286 		break;
287 
288 	      /* make sure the option can be extracted */
289 	      if(off + tmp[1] > dl->dl_tcp_hl)
290 		break;
291 
292 	      if(tmp[0] == 2 && tmp[1] == 4) /* mss option */
293 		dl->dl_tcp_mss = bytes_ntohs(tmp+2);
294 
295 	      if(tmp[0] == 4 && tmp[1] == 2) /* sack permitted option */
296 		dl->dl_tcp_opts |= SCAMPER_DL_TCP_OPT_SACKP;
297 
298 	      if(tmp[0] == 8 && tmp[1] == 10) /* timestamps */
299 		{
300 		  dl->dl_tcp_opts |= SCAMPER_DL_TCP_OPT_TS;
301 		  dl->dl_tcp_tsval = bytes_ntohl(tmp+2);
302 		  dl->dl_tcp_tsecr = bytes_ntohl(tmp+6);
303 		}
304 
305 	      if(tmp[0] == 5)
306 		{
307 		  if(tmp[1]==10 || tmp[1]==18 || tmp[1]==26 || tmp[1]==34)
308 		    {
309 		      dl->dl_tcp_sack_edgec = (tmp[1]-2) / 4;
310 		      for(i=0; i<(tmp[1]-2)/4; i++)
311 			dl->dl_tcp_sack_edges[i] = bytes_ntohl(tmp+2 + (i*4));
312 		    }
313 		  else
314 		    {
315 		      dl->dl_tcp_sack_edgec = -1;
316 		    }
317 		}
318 
319 	      if(tmp[0] == 34 && tmp[1] >= 2)
320 		{
321 		  dl->dl_tcp_opts |= SCAMPER_DL_TCP_OPT_FO;
322 		  dl->dl_tcp_fo_cookielen = tmp[1] - 2;
323 		  for(i=0; i<dl->dl_tcp_fo_cookielen; i++)
324 		    dl->dl_tcp_fo_cookie[i] = tmp[2+i];
325 		}
326 
327 	      if(tmp[0] == 254 && tmp[1] >= 4 && bytes_ntohs(tmp+2) == 0xF989)
328 		{
329 		  dl->dl_tcp_opts |= SCAMPER_DL_TCP_OPT_FO_EXP;
330 		  dl->dl_tcp_fo_cookielen = tmp[1] - 4;
331 		  for(i=0; i<dl->dl_tcp_fo_cookielen; i++)
332 		    dl->dl_tcp_fo_cookie[i] = tmp[4+i];
333 		}
334 
335 	      off += tmp[1];
336 	    }
337 
338 	  dl->dl_tcp_datalen = dl->dl_ip_size - dl->dl_ip_hl - dl->dl_tcp_hl;
339 	  if(dl->dl_tcp_datalen > 0)
340 	    dl->dl_tcp_data = pkt + dl->dl_tcp_hl;
341 	}
342     }
343   else if(dl->dl_ip_proto == IPPROTO_ICMP)
344     {
345       /* the absolute minimum ICMP header size is 8 bytes */
346       if(ICMP_MINLEN > len)
347 	{
348 	  return 0;
349 	}
350 
351       icmp4 = (struct icmp *)pkt;
352       dl->dl_icmp_type = icmp4->icmp_type;
353       dl->dl_icmp_code = icmp4->icmp_code;
354 
355       switch(dl->dl_icmp_type)
356 	{
357 	case ICMP_UNREACH:
358 	case ICMP_TIMXCEED:
359 	  if(ICMP_MINLEN + (int)sizeof(struct ip) > len)
360 	    {
361 	      return 0;
362 	    }
363 
364 	  if(dl->dl_icmp_type == ICMP_UNREACH &&
365 	     dl->dl_icmp_code == ICMP_UNREACH_NEEDFRAG)
366 	    {
367 	      dl->dl_icmp_nhmtu = ntohs(icmp4->icmp_nextmtu);
368 	    }
369 
370 	  ip4 = &icmp4->icmp_ip;
371 
372 	  dl->dl_icmp_ip_proto = ip4->ip_p;
373 	  dl->dl_icmp_ip_size  = ntohs(ip4->ip_len);
374 	  dl->dl_icmp_ip_id    = ntohs(ip4->ip_id);
375 	  dl->dl_icmp_ip_tos   = ip4->ip_tos;
376 	  dl->dl_icmp_ip_ttl   = ip4->ip_ttl;
377 	  dl->dl_icmp_ip_src   = (uint8_t *)&ip4->ip_src;
378 	  dl->dl_icmp_ip_dst   = (uint8_t *)&ip4->ip_dst;
379 
380 	  /*
381 	   * the ICMP response should include the IP header and the first
382 	   * 8 bytes of the transport header.
383 	   */
384 #ifndef _WIN32
385 	  if((size_t)(ICMP_MINLEN + (ip4->ip_hl << 2) + 8) > len)
386 #else
387 	  if((size_t)(ICMP_MINLEN + ((ip4->ip_vhl & 0xf) << 2) + 8) > len)
388 #endif
389 	    {
390 	      return 0;
391 	    }
392 
393 	  pkt = (uint8_t *)ip4;
394 
395 #ifndef _WIN32
396 	  iplen = (ip4->ip_hl << 2);
397 #else
398 	  iplen = ((ip4->ip_vhl & 0xf) << 2);
399 #endif
400 
401 	  pkt += iplen;
402 
403 	  if(dl->dl_icmp_ip_proto == IPPROTO_UDP)
404 	    {
405 	      udp = (struct udphdr *)pkt;
406 	      dl->dl_icmp_udp_sport = ntohs(udp->uh_sport);
407 	      dl->dl_icmp_udp_dport = ntohs(udp->uh_dport);
408 	      dl->dl_icmp_udp_sum   = udp->uh_sum;
409 	    }
410 	  else if(dl->dl_icmp_ip_proto == IPPROTO_ICMP)
411 	    {
412 	      icmp4 = (struct icmp *)pkt;
413 	      dl->dl_icmp_icmp_type = icmp4->icmp_type;
414 	      dl->dl_icmp_icmp_code = icmp4->icmp_code;
415 	      dl->dl_icmp_icmp_id   = ntohs(icmp4->icmp_id);
416 	      dl->dl_icmp_icmp_seq  = ntohs(icmp4->icmp_seq);
417 	    }
418 	  else if(dl->dl_icmp_ip_proto == IPPROTO_TCP)
419 	    {
420 	      tcp = (struct tcphdr *)pkt;
421 	      dl->dl_icmp_tcp_sport = ntohs(tcp->th_sport);
422 	      dl->dl_icmp_tcp_dport = ntohs(tcp->th_dport);
423 	      dl->dl_icmp_tcp_seq   = ntohl(tcp->th_seq);
424 	    }
425 	  break;
426 
427 	case ICMP_ECHOREPLY:
428 	case ICMP_ECHO:
429 	case ICMP_TSTAMPREPLY:
430 	case ICMP_TSTAMP:
431 	  dl->dl_icmp_id  = ntohs(icmp4->icmp_id);
432 	  dl->dl_icmp_seq = ntohs(icmp4->icmp_seq);
433 	  break;
434 
435 	default:
436 	  return 0;
437 	}
438 
439       dl->dl_flags |= SCAMPER_DL_REC_FLAG_TRANS;
440     }
441   else if(dl->dl_ip_proto == IPPROTO_ICMPV6)
442     {
443       /* the absolute minimum ICMP header size is 8 bytes */
444       if((int)sizeof(struct icmp6_hdr) > len)
445 	{
446 	  return 0;
447 	}
448 
449       icmp6 = (struct icmp6_hdr *)pkt;
450       dl->dl_icmp_type = icmp6->icmp6_type;
451       dl->dl_icmp_code = icmp6->icmp6_code;
452       pkt += sizeof(struct icmp6_hdr);
453       len -= sizeof(struct icmp6_hdr);
454 
455       switch(dl->dl_icmp_type)
456 	{
457 	case ICMP6_TIME_EXCEEDED:
458 	case ICMP6_DST_UNREACH:
459 	case ICMP6_PACKET_TOO_BIG:
460 	  if((int)sizeof(struct ip6_hdr) + 8 > len)
461 	    {
462 	      return 0;
463 	    }
464 
465 	  if(dl->dl_icmp_type == ICMP6_PACKET_TOO_BIG)
466 	    {
467 #ifndef _WIN32
468 	      dl->dl_icmp_nhmtu = (ntohl(icmp6->icmp6_mtu) % 0xffff);
469 #else
470 	      dl->dl_icmp_nhmtu = ntohs(icmp6->icmp6_seq);
471 #endif
472 	    }
473 
474 	  ip6 = (struct ip6_hdr *)pkt;
475 	  pkt += sizeof(struct ip6_hdr);
476 
477 	  dl->dl_icmp_ip_proto = ip6->ip6_nxt;
478 	  dl->dl_icmp_ip_size  = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr);
479 	  dl->dl_icmp_ip_hlim  = ip6->ip6_hlim;
480 	  dl->dl_icmp_ip_flow  = ntohl(ip6->ip6_flow) & 0xfffff;
481 	  dl->dl_icmp_ip_src = (uint8_t *)&ip6->ip6_src;
482 	  dl->dl_icmp_ip_dst = (uint8_t *)&ip6->ip6_dst;
483 
484 	  if(dl->dl_icmp_ip_proto == IPPROTO_UDP)
485 	    {
486 	      udp = (struct udphdr *)pkt;
487 	      dl->dl_icmp_udp_sport = ntohs(udp->uh_sport);
488 	      dl->dl_icmp_udp_dport = ntohs(udp->uh_dport);
489 	      dl->dl_icmp_udp_sum   = udp->uh_sum;
490 	    }
491 	  else if(dl->dl_icmp_ip_proto == IPPROTO_ICMPV6)
492 	    {
493 	      icmp6 = (struct icmp6_hdr *)pkt;
494 	      dl->dl_icmp_icmp_type = icmp6->icmp6_type;
495 	      dl->dl_icmp_icmp_code = icmp6->icmp6_code;
496 	      dl->dl_icmp_icmp_id   = ntohs(icmp6->icmp6_id);
497 	      dl->dl_icmp_icmp_seq  = ntohs(icmp6->icmp6_seq);
498 	    }
499 	  else if(dl->dl_icmp_ip_proto == IPPROTO_TCP)
500 	    {
501 	      tcp = (struct tcphdr *)pkt;
502 	      dl->dl_icmp_tcp_sport = ntohs(tcp->th_sport);
503 	      dl->dl_icmp_tcp_dport = ntohs(tcp->th_dport);
504 	      dl->dl_icmp_tcp_seq   = ntohl(tcp->th_seq);
505 	    }
506 	  break;
507 
508 	case ICMP6_ECHO_REPLY:
509 	case ICMP6_ECHO_REQUEST:
510 	  dl->dl_icmp_id  = ntohs(icmp6->icmp6_id);
511 	  dl->dl_icmp_seq = ntohs(icmp6->icmp6_seq);
512 	  break;
513 
514 	case ND_NEIGHBOR_ADVERT:
515 	  dl->dl_icmp6_nd_target   = pkt;
516 	  dl->dl_icmp6_nd_opts     = pkt + 16;
517 	  dl->dl_icmp6_nd_opts_len = len - 16;
518 	  break;
519 
520 	default:
521 	  return 0;
522 	}
523 
524       dl->dl_flags |= SCAMPER_DL_REC_FLAG_TRANS;
525     }
526   else
527     {
528       return 0;
529     }
530 
531   return 1;
532 }
533 
534 /*
535  * dlt_raw_cb
536  *
537  * handle raw IP frames.
538  * i'm not sure how many of these interface types there are, but the linux
539  * sit interface is an example of one that is...
540  *
541  */
542 static int dlt_raw_cb(scamper_dl_rec_t *dl, uint8_t *pkt, size_t len)
543 {
544   int ret;
545 
546   if((ret = dl_parse_ip(dl, pkt, len)) != 0)
547     {
548       dl->dl_type = SCAMPER_DL_TYPE_RAW;
549       dl->dl_net_raw = pkt;
550       dl->dl_net_rawlen = len;
551     }
552 
553   return ret;
554 }
555 
556 /*
557  * dlt_null_cb
558  *
559  * handle the BSD loopback encapsulation.  the first 4 bytes say what protocol
560  * family is used.  filter out anything that is not IPv4 / IPv6
561  *
562  */
563 #ifdef HAVE_BPF
564 static int dlt_null_cb(scamper_dl_rec_t *dl, uint8_t *pkt, size_t len)
565 {
566   uint32_t pf;
567   int ret;
568 
569   /* ensure the packet holds at least 4 bytes for the psuedo header */
570   if(len <= 4)
571     {
572       return 0;
573     }
574 
575   memcpy(&pf, pkt, 4);
576   if(pf == PF_INET || pf == PF_INET6)
577     {
578       if((ret = dl_parse_ip(dl, pkt+4, len-4)) != 0)
579 	{
580 	  dl->dl_type = SCAMPER_DL_TYPE_NULL;
581 	  dl->dl_net_raw = pkt+4;
582 	  dl->dl_net_rawlen = len-4;
583 	}
584 
585       return ret;
586     }
587 
588   return 0;
589 }
590 #endif
591 
592 /*
593  * dlt_en10mb_cb
594  *
595  * handle ethernet frames.
596  *
597  * an ethernet frame consists of
598  *   - 6 bytes dst mac
599  *   - 6 bytes src mac
600  *   - 2 bytes type
601  *
602  */
603 static int dlt_en10mb_cb(scamper_dl_rec_t *dl, uint8_t *pkt, size_t len)
604 {
605   uint16_t u16;
606   size_t off;
607 
608   /* ensure the packet holds at least the length of the ethernet header */
609   if(len <= 14)
610     return 0;
611 
612   u16 = bytes_ntohs(pkt+12);
613   if(u16 == ETHERTYPE_IP || u16 == ETHERTYPE_IPV6)
614     {
615       if(dl_parse_ip(dl, pkt+14, len-14) == 0)
616 	return 0;
617     }
618   else if(u16 == ETHERTYPE_ARP)
619     {
620       /* need to at least have a header */
621       if(14 + 8 >= len)
622 	return 0;
623 
624       off = 14;
625       dl->dl_arp_hrd = bytes_ntohs(pkt+off); off += 2;
626       dl->dl_arp_pro = bytes_ntohs(pkt+off); off += 2;
627       dl->dl_arp_hln = pkt[off++];
628       dl->dl_arp_pln = pkt[off++];
629       dl->dl_arp_op  = bytes_ntohs(pkt+off); off += 2;
630 
631       /* make sure all the bits are found after the arp header */
632       if(14 + 8 + (dl->dl_arp_hln*2) + (dl->dl_arp_pln*2) > len)
633 	return 0;
634 
635       dl->dl_arp_sha = pkt+off; off += dl->dl_arp_hln;
636       dl->dl_arp_spa = pkt+off; off += dl->dl_arp_pln;
637       dl->dl_arp_tha = pkt+off; off += dl->dl_arp_hln;
638       dl->dl_arp_tpa = pkt+off;
639 
640       /* completed record is an arp frame */
641       dl->dl_net_type = SCAMPER_DL_REC_NET_TYPE_ARP;
642     }
643   else return 0;
644 
645   dl->dl_type       = SCAMPER_DL_TYPE_ETHERNET;
646   dl->dl_lladdr_dst = pkt;
647   dl->dl_lladdr_src = pkt+6;
648   dl->dl_net_raw    = pkt+14;
649   dl->dl_net_rawlen = len-14;
650 
651   return 1;
652 }
653 
654 /*
655  * dlt_firewire_cb
656  *
657  * handle IP frames on firewire devices.  a firewire layer-2 frame consists
658  * of two 8 byte EUI64 addresses which represent the dst and the src
659  * addresses, and a 2 byte ethertype
660  */
661 #ifdef HAVE_FIREWIRE
662 static int dlt_firewire_cb(scamper_dl_rec_t *dl, uint8_t *pkt, size_t len)
663 {
664   int ret;
665   uint16_t type;
666 
667   /* ensure the packet holds at least the length of the firewire header */
668   if(len <= 18)
669     {
670       return 0;
671     }
672 
673   memcpy(&type, pkt+16, 2); type = ntohs(type);
674   if(type == ETHERTYPE_IP || type == ETHERTYPE_IPV6)
675     {
676       if((ret = dl_parse_ip(dl, pkt+18, len-18)) != 0)
677 	{
678 	  dl->dl_type = SCAMPER_DL_TYPE_FIREWIRE;
679 	  dl->dl_lladdr_dst = pkt;
680 	  dl->dl_lladdr_src = pkt + 8;
681 	  dl->dl_net_raw    = pkt + 18;
682 	  dl->dl_net_rawlen = len - 18;
683 	}
684 
685       return ret;
686     }
687 
688   return 0;
689 }
690 #endif
691 
692 #if defined(HAVE_BPF)
693 static int dl_bpf_open_dev(char *dev, const size_t len)
694 {
695   int i=0, fd;
696 
697   do
698     {
699       snprintf(dev, len, "/dev/bpf%d", i);
700       if((fd = open(dev, O_RDWR)) == -1)
701 	{
702 	  if(errno == EBUSY)
703 	    {
704 	      continue;
705 	    }
706 	  else
707 	    {
708 	      printerror(__func__, "could not open %s", dev);
709 	      return -1;
710 	    }
711 	}
712       else break;
713     }
714   while(++i < 32768);
715 
716   return fd;
717 }
718 
719 static int dl_bpf_open(const int ifindex)
720 {
721   struct ifreq ifreq;
722   char dev[16];
723   u_int blen;
724   int fd = -1;
725 
726   /* work out the name corresponding to the ifindex */
727   memset(&ifreq, 0, sizeof(ifreq));
728   if(if_indextoname((unsigned int)ifindex, ifreq.ifr_name) == NULL)
729     {
730       printerror(__func__, "if_indextoname failed");
731       goto err;
732     }
733 
734   if((fd = dl_bpf_open_dev(dev, sizeof(dev))) == -1)
735     {
736       goto err;
737     }
738 
739   /* get the suggested read buffer size */
740   if(ioctl(fd, BIOCGBLEN, &blen) == -1)
741     {
742       printerror(__func__, "BIOCGBLEN %s", ifreq.ifr_name);
743       goto err;
744     }
745 
746   /*
747    * try and get the system to use a larger buffer.  need to do this
748    * before the call to BIOCSETIF.
749    */
750   if(blen < 65536)
751     {
752       blen = 65536;
753       if(ioctl(fd, BIOCSBLEN, &blen) == -1)
754 	{
755 	  printerror(__func__, "BIOCSBLEN %s: %d", ifreq.ifr_name, blen);
756 	  goto err;
757 	}
758     }
759 
760   /* set the interface that will be sniffed */
761   if(ioctl(fd, BIOCSETIF, &ifreq) == -1)
762     {
763       printerror(__func__, "%s BIOCSETIF %s failed", dev, ifreq.ifr_name);
764       goto err;
765     }
766 
767   return fd;
768 
769  err:
770   if(fd != -1) close(fd);
771   return -1;
772 }
773 
774 static int dl_bpf_node_init(const scamper_fd_t *fdn, scamper_dl_t *node)
775 {
776   char ifname[IFNAMSIZ];
777   u_int tmp;
778   int ifindex, fd;
779   uint8_t *buf;
780 
781   /* get the file descriptor associated with the fd node */
782   if((fd = scamper_fd_fd_get(fdn)) < 0)
783     {
784       goto err;
785     }
786 
787   /* get the interface index */
788   if(scamper_fd_ifindex(fdn, &ifindex) != 0)
789     {
790       goto err;
791     }
792 
793   /* convert the interface index to a name */
794   if(if_indextoname((unsigned int)ifindex, ifname) == NULL)
795     {
796       printerror(__func__,"if_indextoname %d failed", ifindex);
797       goto err;
798     }
799 
800   /* get the read buffer size */
801   if(ioctl(fd, BIOCGBLEN, &node->readbuf_len) == -1)
802     {
803       printerror(__func__, "bpf BIOCGBLEN %s failed", ifname);
804       goto err;
805     }
806 
807   /* get the DLT type for the interface */
808   if(ioctl(fd, BIOCGDLT, &tmp) == -1)
809     {
810       printerror(__func__, "bpf BIOCGDLT %s failed", ifname);
811       goto err;
812     }
813   node->type = tmp;
814 
815   switch(node->type)
816     {
817     case DLT_NULL:
818       node->dlt_cb = dlt_null_cb;
819       if(osinfo->os_id == SCAMPER_OSINFO_OS_FREEBSD &&
820 	 osinfo->os_rel_dots > 0 && osinfo->os_rel[0] >= 6)
821 	{
822 	  node->tx_type = SCAMPER_DL_TX_NULL;
823 	}
824       else
825 	{
826 	  node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
827 	}
828       break;
829 
830     case DLT_EN10MB:
831       node->dlt_cb = dlt_en10mb_cb;
832       node->tx_type = SCAMPER_DL_TX_ETHERNET;
833       break;
834 
835     case DLT_RAW:
836       node->dlt_cb = dlt_raw_cb;
837       node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
838       break;
839 
840 #if defined(DLT_APPLE_IP_OVER_IEEE1394)
841     case DLT_APPLE_IP_OVER_IEEE1394:
842       node->dlt_cb = dlt_firewire_cb;
843       node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
844       break;
845 #endif
846 
847     default:
848       scamper_debug(__func__, "%s unhandled datalink %d", ifname, node->type);
849       goto err;
850     }
851 
852   scamper_debug(__func__, "bpf if %s index %d buflen %d datalink %d",
853 		ifname, ifindex, node->readbuf_len, node->type);
854 
855   tmp = 1;
856   if(ioctl(fd, BIOCIMMEDIATE, &tmp) == -1)
857     {
858       printerror(__func__, "bpf BIOCIMMEDIATE failed");
859       goto err;
860     }
861 
862   if(readbuf_len < node->readbuf_len)
863     {
864       if((buf = realloc(readbuf, node->readbuf_len)) == NULL)
865 	{
866 	  printerror(__func__, "could not realloc");
867 	  return -1;
868 	}
869       readbuf     = buf;
870       readbuf_len = node->readbuf_len;
871     }
872 
873   return 0;
874 
875  err:
876   return -1;
877 }
878 
879 static int dl_bpf_init(void)
880 {
881   struct bpf_version bv;
882   int  fd;
883   char buf[16];
884   int  err;
885 
886   if((fd = dl_bpf_open_dev(buf, sizeof(buf))) == -1)
887     {
888       if(errno == ENXIO)
889 	{
890 	  return 0;
891 	}
892       return -1;
893     }
894 
895   err = ioctl(fd, BIOCVERSION, &bv);
896   close(fd);
897   if(err == -1)
898     {
899       printerror(__func__, "BIOCVERSION failed");
900       return -1;
901     }
902 
903   scamper_debug(__func__, "bpf version %d.%d", bv.bv_major, bv.bv_minor);
904   if(bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION)
905     {
906       printerror_msg(__func__, "bpf ver %d.%d is incompatible with %d.%d",
907 		     bv.bv_major, bv.bv_minor,
908 		     BPF_MAJOR_VERSION, BPF_MINOR_VERSION);
909       return -1;
910     }
911 
912   osinfo = scamper_osinfo_get();
913   if(osinfo->os_id == SCAMPER_OSINFO_OS_FREEBSD &&
914      osinfo->os_rel_dots >= 2 && osinfo->os_rel[0] == 4 &&
915      (osinfo->os_rel[1] == 3 || osinfo->os_rel[1] == 4))
916     {
917       printerror_msg(__func__,
918 		     "BPF file descriptors do not work with "
919 		     "select in FreeBSD 4.3 or 4.4");
920       return -1;
921     }
922 
923   return 0;
924 }
925 
926 static int dl_bpf_read(const int fd, scamper_dl_t *node)
927 {
928   struct bpf_hdr    *bpf_hdr;
929   scamper_dl_rec_t   dl;
930   ssize_t            len;
931   uint8_t           *buf = readbuf;
932 
933   while((len = read(fd, buf, node->readbuf_len)) == -1)
934     {
935       if(errno == EINTR) continue;
936       if(errno == EWOULDBLOCK) return 0;
937       printerror(__func__, "read %d bytes from fd %d failed",
938 		 node->readbuf_len, fd);
939       return -1;
940     }
941 
942   /* record the ifindex now, as the cb may need it */
943   if(scamper_fd_ifindex(node->fdn, &dl.dl_ifindex) != 0)
944     {
945       return -1;
946     }
947 
948   while(buf < readbuf + len)
949     {
950       bpf_hdr = (struct bpf_hdr *)buf;
951 
952       /* reset the datalink record */
953       memset(&dl, 0, sizeof(dl));
954 
955       if(node->dlt_cb(&dl, buf + bpf_hdr->bh_hdrlen, bpf_hdr->bh_caplen))
956 	{
957 	  /* bpf always supplies a timestamp */
958 	  dl.dl_flags |= SCAMPER_DL_REC_FLAG_TIMESTAMP;
959 
960 	  dl.dl_tv.tv_sec  = bpf_hdr->bh_tstamp.tv_sec;
961 	  dl.dl_tv.tv_usec = bpf_hdr->bh_tstamp.tv_usec;
962 
963 	  scamper_task_handledl(&dl);
964 	}
965 
966       buf += BPF_WORDALIGN(bpf_hdr->bh_caplen + bpf_hdr->bh_hdrlen);
967     }
968 
969   return 0;
970 }
971 
972 static int dl_bpf_tx(const scamper_dl_t *node,
973 		     const uint8_t *pkt, const size_t len)
974 {
975   ssize_t wb;
976 
977   if((wb = write(scamper_fd_fd_get(node->fdn), pkt, len)) < (ssize_t)len)
978     {
979       if(wb == -1)
980 	printerror(__func__, "%d bytes failed", len);
981       else
982 	scamper_debug(__func__, "%d bytes sent of %d total", wb, len);
983       return -1;
984     }
985 
986   return 0;
987 }
988 
989 static int dl_bpf_filter(scamper_dl_t *node, struct bpf_insn *insns, int len)
990 {
991   struct bpf_program prog;
992 
993   prog.bf_len   = len;
994   prog.bf_insns = insns;
995 
996   if(ioctl(scamper_fd_fd_get(node->fdn), BIOCSETF, (caddr_t)&prog) == -1)
997     {
998       printerror(__func__, "BIOCSETF failed");
999       return -1;
1000     }
1001 
1002   return 0;
1003 }
1004 
1005 #elif defined(__linux__)
1006 
1007 static int dl_linux_open(const int ifindex)
1008 {
1009   struct sockaddr_ll sll;
1010   int fd;
1011 
1012   /* open the socket in non cooked mode for now */
1013   if((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1)
1014     {
1015       printerror(__func__, "could not open PF_PACKET");
1016       return -1;
1017     }
1018 
1019   /* scamper only wants packets on this interface */
1020   memset(&sll, 0, sizeof(sll));
1021   sll.sll_family   = AF_PACKET;
1022   sll.sll_ifindex  = ifindex;
1023   sll.sll_protocol = htons(ETH_P_ALL);
1024   if(bind(fd, (struct sockaddr *)&sll, sizeof(sll)) == -1)
1025     {
1026       printerror(__func__, "could not bind to %d", ifindex);
1027       close(fd);
1028       return -1;
1029     }
1030 
1031   return fd;
1032 }
1033 
1034 static int dl_linux_node_init(const scamper_fd_t *fdn, scamper_dl_t *node)
1035 {
1036   struct ifreq ifreq;
1037   char ifname[IFNAMSIZ];
1038   int fd, ifindex;
1039 
1040   if(scamper_fd_ifindex(fdn, &ifindex) != 0)
1041     {
1042       goto err;
1043     }
1044 
1045   if((fd = scamper_fd_fd_get(fdn)) < 0)
1046     {
1047       goto err;
1048     }
1049 
1050   if(if_indextoname(ifindex, ifname) == NULL)
1051     {
1052       printerror(__func__, "if_indextoname %d failed", ifindex);
1053       goto err;
1054     }
1055 
1056   /* find out what type of datalink the interface has */
1057   memcpy(ifreq.ifr_name, ifname, sizeof(ifreq.ifr_name));
1058   if(ioctl(fd, SIOCGIFHWADDR, &ifreq) == -1)
1059     {
1060       printerror(__func__, "%s SIOCGIFHWADDR failed", ifname);
1061       goto err;
1062     }
1063 
1064   node->type = ifreq.ifr_hwaddr.sa_family;
1065 
1066   /* scamper can only deal with ethernet datalinks at this time */
1067   switch(node->type)
1068     {
1069     case ARPHRD_ETHER:
1070       node->dlt_cb = dlt_en10mb_cb;
1071       node->tx_type = SCAMPER_DL_TX_ETHERNET;
1072       break;
1073 
1074     case ARPHRD_LOOPBACK:
1075       node->dlt_cb = dlt_en10mb_cb;
1076       node->tx_type = SCAMPER_DL_TX_ETHLOOP;
1077       break;
1078 
1079 #if defined(ARPHRD_SIT)
1080     case ARPHRD_SIT:
1081       node->dlt_cb = dlt_raw_cb;
1082       node->tx_type = SCAMPER_DL_TX_RAW;
1083       break;
1084 #endif
1085 
1086 #if defined(ARPHRD_IEEE1394)
1087     case ARPHRD_IEEE1394:
1088       node->dlt_cb = dlt_firewire_cb;
1089       node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
1090       break;
1091 #endif
1092 
1093 #if defined(ARPHRD_VOID)
1094     case ARPHRD_VOID:
1095       node->dlt_cb = dlt_raw_cb;
1096       node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
1097       break;
1098 #endif
1099 
1100     default:
1101       scamper_debug(__func__, "%s unhandled datalink %d", ifname, node->type);
1102       goto err;
1103     }
1104 
1105   return 0;
1106 
1107  err:
1108   return -1;
1109 }
1110 
1111 static int dl_linux_read(const int fd, scamper_dl_t *node)
1112 {
1113   scamper_dl_rec_t   dl;
1114   ssize_t            len;
1115   struct sockaddr_ll from;
1116   socklen_t          fromlen;
1117 
1118   fromlen = sizeof(from);
1119   while((len = recvfrom(fd, readbuf, readbuf_len, MSG_TRUNC,
1120 			(struct sockaddr *)&from, &fromlen)) == -1)
1121     {
1122       if(errno == EINTR)
1123 	{
1124 	  fromlen = sizeof(from);
1125 	  continue;
1126 	}
1127       if(errno == EAGAIN)
1128 	{
1129 	  return 0;
1130 	}
1131       printerror(__func__, "read %d bytes from fd %d failed", readbuf_len, fd);
1132       return -1;
1133     }
1134 
1135   /* sanity check the packet length */
1136   if(len > readbuf_len) len = readbuf_len;
1137 
1138   /* reset the datalink record */
1139   memset(&dl, 0, sizeof(dl));
1140 
1141   /* record the ifindex now, as the cb routine may need it */
1142   if(scamper_fd_ifindex(node->fdn, &dl.dl_ifindex) != 0)
1143     {
1144       return -1;
1145     }
1146 
1147   /* if the packet passes the filter, we need to get the time it was rx'd */
1148   if(node->dlt_cb(&dl, readbuf, len))
1149     {
1150       /* scamper treats the failure of this ioctl as non-fatal */
1151       if(ioctl(fd, SIOCGSTAMP, &dl.dl_tv) == 0)
1152 	{
1153 	  dl.dl_flags |= SCAMPER_DL_REC_FLAG_TIMESTAMP;
1154 	}
1155       else
1156 	{
1157 	  printerror(__func__, "could not SIOCGSTAMP on fd %d", fd);
1158 	}
1159 
1160       scamper_task_handledl(&dl);
1161     }
1162 
1163   return 0;
1164 }
1165 
1166 static int dl_linux_tx(const scamper_dl_t *node,
1167 		       const uint8_t *pkt, const size_t len)
1168 {
1169   struct sockaddr_ll sll;
1170   struct sockaddr *sa = (struct sockaddr *)&sll;
1171   ssize_t wb;
1172   int fd, ifindex;
1173 
1174   if(scamper_fd_ifindex(node->fdn, &ifindex) != 0)
1175     {
1176       return -1;
1177     }
1178 
1179   memset(&sll, 0, sizeof(sll));
1180   sll.sll_family = AF_PACKET;
1181   sll.sll_ifindex = ifindex;
1182 
1183   if(node->type == ARPHRD_SIT)
1184     sll.sll_protocol = htons(ETH_P_IPV6);
1185   else
1186     sll.sll_protocol = htons(ETH_P_ALL);
1187 
1188   fd = scamper_fd_fd_get(node->fdn);
1189 
1190   if((wb = sendto(fd, pkt, len, 0, sa, sizeof(sll))) < (ssize_t)len)
1191     {
1192       if(wb == -1)
1193 	printerror(__func__, "%d bytes failed", len);
1194       else
1195 	scamper_debug(__func__, "%d bytes sent of %d total", wb, len);
1196       return -1;
1197     }
1198 
1199   return 0;
1200 }
1201 
1202 static int dl_linux_filter(scamper_dl_t *node,
1203 			   struct sock_filter *insns, int len)
1204 {
1205   struct sock_fprog prog;
1206   int i;
1207 
1208   for(i=0; i<len; i++)
1209     {
1210       if(insns[i].code == (BPF_RET+BPF_K) && insns[i].k > 0)
1211 	{
1212 	  insns[i].k = 65535;
1213 	}
1214     }
1215 
1216   prog.len    = len;
1217   prog.filter = insns;
1218 
1219   if(setsockopt(scamper_fd_fd_get(node->fdn), SOL_SOCKET, SO_ATTACH_FILTER,
1220 		(caddr_t)&prog, sizeof(prog)) == -1)
1221     {
1222       printerror(__func__, "SO_ATTACH_FILTER failed");
1223       return -1;
1224     }
1225 
1226   return 0;
1227 }
1228 
1229 #elif defined(HAVE_DLPI)
1230 
1231 static int dl_dlpi_open(const int ifindex)
1232 {
1233   char ifname[5+IFNAMSIZ];
1234   int fd;
1235 
1236   strncpy(ifname, "/dev/", sizeof(ifname));
1237   if(if_indextoname(ifindex, ifname+5) == NULL)
1238     {
1239       printerror(__func__, "if_indextoname %d failed", ifindex);
1240       return -1;
1241     }
1242 
1243   if((fd = open(ifname, O_RDWR)) == -1)
1244     {
1245       printerror(__func__, "could not open %s", ifname);
1246       return -1;
1247     }
1248 
1249   return fd;
1250 }
1251 
1252 static int dl_dlpi_req(const int fd, void *req, size_t len)
1253 {
1254   union	DL_primitives *dlp;
1255   struct strbuf ctl;
1256 
1257   ctl.maxlen = 0;
1258   ctl.len = len;
1259   ctl.buf = (char *)req;
1260 
1261   if(putmsg(fd, &ctl, NULL, 0) == -1)
1262     {
1263       dlp = req;
1264       printerror(__func__, "could not putmsg %d", dlp->dl_primitive);
1265       return -1;
1266     }
1267 
1268   return 0;
1269 }
1270 
1271 static int dl_dlpi_ack(const int fd, void *ack, int primitive)
1272 {
1273   union	DL_primitives *dlp;
1274   struct strbuf ctl;
1275   int flags;
1276 
1277   flags = 0;
1278   ctl.maxlen = MAXDLBUF;
1279   ctl.len = 0;
1280   ctl.buf = (char *)ack;
1281   if(getmsg(fd, &ctl, NULL, &flags) == -1)
1282     {
1283       printerror(__func__, "could not getmsg %d", primitive);
1284       return -1;
1285     }
1286 
1287   dlp = ack;
1288   if(dlp->dl_primitive != primitive)
1289     {
1290       scamper_debug(__func__,
1291 		    "expected %d, got %d", primitive, dlp->dl_primitive);
1292       return -1;
1293     }
1294 
1295   return 0;
1296 }
1297 
1298 static int dl_dlpi_promisc(const int fd, const int level)
1299 {
1300   dl_promiscon_req_t promiscon_req;
1301   uint32_t buf[MAXDLBUF];
1302 
1303   promiscon_req.dl_primitive = DL_PROMISCON_REQ;
1304   promiscon_req.dl_level = level;
1305   if(dl_dlpi_req(fd, &promiscon_req, sizeof(promiscon_req)) == -1)
1306     {
1307       return -1;
1308     }
1309 
1310   /* check for an ack to the promisc req */
1311   if(dl_dlpi_ack(fd, buf, DL_OK_ACK) == -1)
1312     {
1313       return -1;
1314     }
1315 
1316   return 0;
1317 }
1318 
1319 static int strioctl(int fd, int cmd, void *dp, int len)
1320 {
1321   struct strioctl str;
1322 
1323   str.ic_cmd = cmd;
1324   str.ic_timout = -1;
1325   str.ic_len = len;
1326   str.ic_dp = (char *)dp;
1327   if(ioctl(fd, I_STR, &str) == -1)
1328     {
1329       return -1;
1330     }
1331 
1332   return str.ic_len;
1333 }
1334 
1335 static int dl_dlpi_node_init(const scamper_fd_t *fdn, scamper_dl_t *node)
1336 {
1337   uint32_t         buf[MAXDLBUF];
1338   struct timeval   tv;
1339   dl_info_req_t    info_req;
1340   dl_info_ack_t   *info_ack;
1341   dl_attach_req_t  attach_req;
1342   dl_bind_req_t    bind_req;
1343   int              i, fd;
1344 
1345 #ifndef NDEBUG
1346   char             ifname[IFNAMSIZ];
1347   int              ifindex;
1348 #endif
1349 
1350   if((fd = scamper_fd_fd_get(fdn)) < 0)
1351     {
1352       return -1;
1353     }
1354 
1355   /*
1356    * send an information request to the datalink to determine what type
1357    * of packets they supply
1358    */
1359   info_req.dl_primitive = DL_INFO_REQ;
1360   if(dl_dlpi_req(fd, &info_req, sizeof(info_req)) == -1)
1361     {
1362       return -1;
1363     }
1364 
1365   /*
1366    * read the information acknowledgement, which contains details on the
1367    * type of the interface, etc.
1368    */
1369   if(dl_dlpi_ack(fd, buf, DL_INFO_ACK) == -1)
1370     {
1371       return -1;
1372     }
1373   info_ack = (dl_info_ack_t *)buf;
1374 
1375   /* record the mac type with the node */
1376   node->type = info_ack->dl_mac_type;
1377 
1378   /* determine how to handle the datalink */
1379   switch(node->type)
1380     {
1381     case DL_CSMACD:
1382     case DL_ETHER:
1383       node->dlt_cb = dlt_en10mb_cb;
1384       node->tx_type = SCAMPER_DL_TX_ETHERNET;
1385       break;
1386 
1387     default:
1388       node->tx_type = SCAMPER_DL_TX_UNSUPPORTED;
1389       scamper_debug(__func__, "unhandled datalink %d", node->type);
1390       return -1;
1391     }
1392 
1393   /* attach to the interface */
1394   if(info_ack->dl_provider_style == DL_STYLE2)
1395     {
1396       attach_req.dl_primitive = DL_ATTACH_REQ;
1397       attach_req.dl_ppa = 0;
1398       if(dl_dlpi_req(fd, &attach_req, sizeof(attach_req)) == -1)
1399 	{
1400 	  return -1;
1401 	}
1402 
1403       /* check for a generic ack */
1404       if(dl_dlpi_ack(fd, buf, DL_OK_ACK) == -1)
1405 	{
1406 	  return -1;
1407 	}
1408     }
1409 
1410   /* bind the interface */
1411   memset(&bind_req, 0, sizeof(bind_req));
1412   bind_req.dl_primitive = DL_BIND_REQ;
1413   bind_req.dl_service_mode = DL_CLDLS;
1414   if(dl_dlpi_req(fd, &bind_req, sizeof(bind_req)) == -1)
1415     {
1416       return -1;
1417     }
1418 
1419   /* check for an ack to the bind */
1420   if(dl_dlpi_ack(fd, buf, DL_BIND_ACK) == -1)
1421     {
1422       return -1;
1423     }
1424 
1425   /*
1426    * turn on phys and sap promisc modes.  dlpi will not supply outbound
1427    * probe packets unless in phys promisc mode.
1428    */
1429   if(dl_dlpi_promisc(fd, DL_PROMISC_PHYS) == -1 ||
1430      dl_dlpi_promisc(fd, DL_PROMISC_SAP) == -1)
1431     {
1432       return -1;
1433     }
1434 
1435   /* get full link layer */
1436   if(strioctl(fd, DLIOCRAW, NULL, 0) == -1)
1437     {
1438       printerror(__func__, "could not DLIOCRAW");
1439       return -1;
1440     }
1441 
1442   /* push bufmod */
1443   if(ioctl(fd, I_PUSH, "bufmod") == -1)
1444     {
1445       printerror(__func__, "could not push bufmod");
1446       return -1;
1447     }
1448 
1449   /* we need the first 1500 bytes of the packet */
1450   i = 1500;
1451   if(strioctl(fd, SBIOCSSNAP, &i, sizeof(i)) == -1)
1452     {
1453       printerror(__func__, "could not SBIOCSSNAP %d", i);
1454       return -1;
1455     }
1456 
1457   /* send the data every 50ms */
1458   tv.tv_sec = 0;
1459   tv.tv_usec = 50000;
1460   if(strioctl(fd, SBIOCSTIME, &tv, sizeof(tv)) == -1)
1461     {
1462       printerror(__func__, "could not SBIOCSTIME %d.%06d",
1463 		 tv.tv_sec, tv.tv_usec);
1464       return -1;
1465     }
1466 
1467   /* set the chunk length */
1468   i = 65535;
1469   if(strioctl(fd, SBIOCSCHUNK, &i, sizeof(i)) == -1)
1470     {
1471       printerror(__func__, "could not SBIOCSCHUNK %d", i);
1472       return -1;
1473     }
1474 
1475   if(ioctl(fd, I_FLUSH, FLUSHR) == -1)
1476     {
1477       printerror(__func__, "could not flushr");
1478       return -1;
1479     }
1480 
1481 #ifndef NDEBUG
1482   if(scamper_fd_ifindex(fdn, &ifindex) != 0 ||
1483      if_indextoname(ifindex, ifname) == NULL)
1484     {
1485       strncpy(ifname, "<null>", sizeof(ifname)-1);
1486       ifname[sizeof(ifname)-1] = '\0';
1487     }
1488   scamper_debug(__func__, "dlpi if %s index %d datalink %d",
1489 		ifname, ifindex, node->type);
1490 #endif
1491 
1492   return 0;
1493 }
1494 
1495 static int dl_dlpi_read(const int fd, scamper_dl_t *node)
1496 {
1497   scamper_dl_rec_t  dl;
1498   struct strbuf     data;
1499   struct sb_hdr    *sbh;
1500   uint8_t          *buf = readbuf;
1501   int               flags;
1502 
1503   flags = 0;
1504   data.buf = (void *)readbuf;
1505   data.maxlen = readbuf_len;
1506   data.len = 0;
1507 
1508   if(getmsg(fd, NULL, &data, &flags) == -1)
1509     {
1510       printerror(__func__, "could not getmsg");
1511       return -1;
1512     }
1513 
1514   while(buf < readbuf + data.len)
1515     {
1516       sbh = (struct sb_hdr *)buf;
1517 
1518       memset(&dl, 0, sizeof(dl));
1519       dl.dl_flags = SCAMPER_DL_REC_FLAG_TIMESTAMP;
1520 
1521       if(node->dlt_cb(&dl, buf + sizeof(struct sb_hdr), sbh->sbh_msglen))
1522 	{
1523 	  dl.dl_tv.tv_sec  = sbh->sbh_timestamp.tv_sec;
1524 	  dl.dl_tv.tv_usec = sbh->sbh_timestamp.tv_usec;
1525 	  scamper_task_handledl(&dl);
1526 	}
1527 
1528       buf += sbh->sbh_totlen;
1529     }
1530 
1531   return -1;
1532 }
1533 
1534 static int dl_dlpi_tx(const scamper_dl_t *node,
1535 		      const uint8_t *pkt, const size_t len)
1536 {
1537   struct strbuf data;
1538   int fd;
1539 
1540   if((fd = scamper_fd_fd_get(node->fdn)) < 0)
1541     return -1;
1542 
1543   memset(&data, 0, sizeof(data));
1544   data.buf = (void *)pkt;
1545   data.len = len;
1546 
1547   if(putmsg(fd, NULL, &data, 0) != 0)
1548     {
1549       printerror(__func__, "could not putmsg");
1550       return -1;
1551     }
1552 
1553   return 0;
1554 }
1555 
1556 #endif
1557 
1558 #if defined(HAVE_BPF_FILTER)
1559 
1560 #if defined(HAVE_BPF)
1561 static void bpf_stmt(struct bpf_insn *insn, uint16_t code, uint32_t k)
1562 #else
1563 static void bpf_stmt(struct sock_filter *insn, uint16_t code, uint32_t k)
1564 #endif
1565 {
1566   insn->code = code;
1567   insn->jt   = 0;
1568   insn->jf   = 0;
1569   insn->k    = k;
1570   return;
1571 }
1572 
1573 static int dl_filter(scamper_dl_t *node)
1574 {
1575 #if defined(HAVE_BPF)
1576   struct bpf_insn insns[1];
1577 #else
1578   struct sock_filter insns[1];
1579 #endif
1580 
1581   bpf_stmt(&insns[0], BPF_RET+BPF_K, 65535);
1582 
1583 #if defined(HAVE_BPF)
1584   if(dl_bpf_filter(node, insns, 1) == -1)
1585 #elif defined(__linux__)
1586   if(dl_linux_filter(node, insns, 1) == -1)
1587 #endif
1588     {
1589       return -1;
1590     }
1591 
1592    return 0;
1593 }
1594 #endif
1595 
1596 int scamper_dl_rec_src(scamper_dl_rec_t *dl, scamper_addr_t *addr)
1597 {
1598   if(dl->dl_af == AF_INET)
1599     addr->type = SCAMPER_ADDR_TYPE_IPV4;
1600   else if(dl->dl_af == AF_INET6)
1601     addr->type = SCAMPER_ADDR_TYPE_IPV6;
1602   else
1603     return -1;
1604 
1605   addr->addr = dl->dl_ip_src;
1606   return 0;
1607 }
1608 
1609 int scamper_dl_rec_icmp_ip_dst(scamper_dl_rec_t *dl, scamper_addr_t *addr)
1610 {
1611   if(dl->dl_af == AF_INET)
1612     addr->type = SCAMPER_ADDR_TYPE_IPV4;
1613   else if(dl->dl_af == AF_INET6)
1614     addr->type = SCAMPER_ADDR_TYPE_IPV6;
1615   else
1616     return -1;
1617 
1618   addr->addr = dl->dl_icmp_ip_dst;
1619   return 0;
1620 }
1621 
1622 #if !defined(NDEBUG) && !defined(WITHOUT_DEBUGFILE)
1623 void scamper_dl_rec_frag_print(const scamper_dl_rec_t *dl)
1624 {
1625   char addr[64];
1626   uint32_t id;
1627 
1628   assert(dl->dl_af == AF_INET || dl->dl_af == AF_INET6);
1629 
1630   if(dl->dl_af == AF_INET)
1631     id = dl->dl_ip_id;
1632   else
1633     id = dl->dl_ip6_id;
1634 
1635   scamper_debug(NULL, "from %s len %d ipid %u off %u",
1636 		addr_tostr(dl->dl_af, dl->dl_ip_src, addr, sizeof(addr)),
1637 		dl->dl_ip_size, id, dl->dl_ip_off);
1638 
1639   return;
1640 }
1641 
1642 void scamper_dl_rec_udp_print(const scamper_dl_rec_t *dl)
1643 {
1644   char addr[64], ipid[16];
1645 
1646   assert(dl->dl_af == AF_INET || dl->dl_af == AF_INET6);
1647   assert(dl->dl_ip_proto == IPPROTO_UDP);
1648 
1649   if(dl->dl_af == AF_INET)
1650     snprintf(ipid, sizeof(ipid), "ipid 0x%04x ", dl->dl_ip_id);
1651   else
1652     ipid[0] = '\0';
1653 
1654   scamper_debug(NULL, "from %s %sudp %d:%d len %d",
1655 		addr_tostr(dl->dl_af, dl->dl_ip_src, addr, sizeof(addr)),
1656 		ipid, dl->dl_tcp_sport, dl->dl_tcp_dport, dl->dl_ip_size);
1657   return;
1658 }
1659 
1660 void scamper_dl_rec_tcp_print(const scamper_dl_rec_t *dl)
1661 {
1662   static const char *tcpflags[] = {
1663     "fin",
1664     "syn",
1665     "rst",
1666     "psh",
1667     "ack",
1668     "urg",
1669     "ece",
1670     "cwr"
1671   };
1672   uint8_t u8;
1673   size_t off;
1674   char addr[64];
1675   char fbuf[32], *flags;
1676   char pos[32];
1677   char ipid[16];
1678   int i;
1679 
1680   assert(dl->dl_af == AF_INET || dl->dl_af == AF_INET6);
1681   assert(dl->dl_ip_proto == IPPROTO_TCP);
1682 
1683   if((u8 = dl->dl_tcp_flags) != 0)
1684     {
1685       flags = fbuf;
1686       for(i=0; i<8; i++)
1687 	{
1688 	  if((dl->dl_tcp_flags & (1<<i)) != 0)
1689 	    {
1690 	      memcpy(flags, tcpflags[i], 3); flags += 3;
1691 	      u8 &= ~(1<<i);
1692 	      if(u8 != 0)
1693 		{
1694 		  *flags = '-';
1695 		  flags++;
1696 		}
1697 	      else break;
1698 	    }
1699 	}
1700       *flags = '\0';
1701       flags = fbuf;
1702     }
1703   else
1704     {
1705       flags = "nil";
1706     }
1707 
1708   off = 0;
1709   string_concat(pos, sizeof(pos), &off, "%u", dl->dl_tcp_seq);
1710   if(dl->dl_tcp_flags & TH_ACK)
1711     string_concat(pos, sizeof(pos), &off, ":%u", dl->dl_tcp_ack);
1712 
1713   if(dl->dl_af == AF_INET)
1714     snprintf(ipid, sizeof(ipid), "ipid 0x%04x ", dl->dl_ip_id);
1715   else
1716     ipid[0] = '\0';
1717 
1718   scamper_debug(NULL, "from %s %stcp %d:%d %s %s len %d",
1719 		addr_tostr(dl->dl_af, dl->dl_ip_src, addr, sizeof(addr)),
1720 		ipid, dl->dl_tcp_sport, dl->dl_tcp_dport, flags, pos,
1721 		dl->dl_ip_size);
1722 
1723   return;
1724 }
1725 
1726 void scamper_dl_rec_icmp_print(const scamper_dl_rec_t *dl)
1727 {
1728   char *t = NULL, tbuf[64];
1729   char *c = NULL, cbuf[64];
1730   char addr[64];
1731   char ip[256];
1732   char icmp[256];
1733   char inner_ip[256];
1734   char inner_transport[256];
1735   size_t off;
1736 
1737   assert(dl->dl_af == AF_INET || dl->dl_af == AF_INET6);
1738 
1739   if(dl->dl_af == AF_INET)
1740     {
1741       addr_tostr(AF_INET, dl->dl_ip_src, addr, sizeof(addr));
1742       snprintf(ip, sizeof(ip), "from %s size %d ttl %d tos 0x%02x ipid 0x%04x",
1743 	       addr, dl->dl_ip_size, dl->dl_ip_ttl, dl->dl_ip_tos,
1744 	       dl->dl_ip_id);
1745 
1746       switch(dl->dl_icmp_type)
1747         {
1748         case ICMP_UNREACH:
1749           t = "unreach";
1750           switch(dl->dl_icmp_code)
1751             {
1752             case ICMP_UNREACH_NET:           c = "net";           break;
1753             case ICMP_UNREACH_HOST:          c = "host";          break;
1754             case ICMP_UNREACH_PROTOCOL:      c = "protocol";      break;
1755             case ICMP_UNREACH_PORT:          c = "port";          break;
1756             case ICMP_UNREACH_SRCFAIL:       c = "src-rt failed"; break;
1757             case ICMP_UNREACH_NET_UNKNOWN:   c = "net unknown";   break;
1758             case ICMP_UNREACH_HOST_UNKNOWN:  c = "host unknown";  break;
1759             case ICMP_UNREACH_ISOLATED:      c = "isolated";      break;
1760             case ICMP_UNREACH_NET_PROHIB:    c = "net prohib";    break;
1761             case ICMP_UNREACH_HOST_PROHIB:   c = "host prohib";   break;
1762             case ICMP_UNREACH_TOSNET:        c = "tos net";       break;
1763             case ICMP_UNREACH_TOSHOST:       c = "tos host";      break;
1764             case ICMP_UNREACH_FILTER_PROHIB: c = "admin prohib";  break;
1765             case ICMP_UNREACH_NEEDFRAG:
1766 	      /*
1767 	       * use the type buf to be consistent with the ICMP6
1768 	       * fragmentation required message
1769 	       */
1770 	      snprintf(tbuf, sizeof(tbuf), "need frag %d", dl->dl_icmp_nhmtu);
1771 	      t = tbuf;
1772 	      break;
1773 
1774             default:
1775 	      snprintf(cbuf, sizeof(cbuf), "code %d", dl->dl_icmp_code);
1776 	      c = cbuf;
1777 	      break;
1778             }
1779           break;
1780 
1781         case ICMP_TIMXCEED:
1782           t = "time exceeded";
1783           switch(dl->dl_icmp_code)
1784             {
1785             case ICMP_TIMXCEED_INTRANS: c = "in trans"; break;
1786             case ICMP_TIMXCEED_REASS:   c = "in reass"; break;
1787             default:
1788 	      snprintf(cbuf, sizeof(cbuf), "code %d", dl->dl_icmp_code);
1789 	      c = cbuf;
1790 	      break;
1791             }
1792           break;
1793 
1794 	case ICMP_ECHOREPLY:
1795 	  t = "echo reply";
1796 	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
1797 		   dl->dl_icmp_id, dl->dl_icmp_seq);
1798 	  c = cbuf;
1799 	  break;
1800 
1801 	case ICMP_TSTAMPREPLY:
1802 	  t = "time reply";
1803 	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
1804 		   dl->dl_icmp_id, dl->dl_icmp_seq);
1805 	  c = cbuf;
1806 	  break;
1807         }
1808     }
1809   else
1810     {
1811       addr_tostr(AF_INET6, dl->dl_ip_src, addr, sizeof(addr));
1812       off = 0;
1813       string_concat(ip, sizeof(ip), &off, "from %s size %d hlim %d", addr,
1814 		    dl->dl_ip_size, dl->dl_ip_hlim);
1815       if(dl->dl_ip_flags & SCAMPER_DL_IP_FLAG_FRAG)
1816 	string_concat(ip, sizeof(ip), &off, " ipid 0x%08x", dl->dl_ip6_id);
1817 
1818       switch(dl->dl_icmp_type)
1819         {
1820         case ICMP6_DST_UNREACH:
1821           t = "unreach";
1822           switch(dl->dl_icmp_code)
1823             {
1824             case ICMP6_DST_UNREACH_NOROUTE:     c = "no route";     break;
1825             case ICMP6_DST_UNREACH_ADMIN:       c = "admin prohib"; break;
1826             case ICMP6_DST_UNREACH_BEYONDSCOPE: c = "beyond scope"; break;
1827             case ICMP6_DST_UNREACH_ADDR:        c = "addr";         break;
1828             case ICMP6_DST_UNREACH_NOPORT:      c = "port";         break;
1829 
1830             default:
1831 	      snprintf(cbuf, sizeof(cbuf), "code %d", dl->dl_icmp_code);
1832 	      c = cbuf;
1833 	      break;
1834             }
1835           break;
1836 
1837         case ICMP6_TIME_EXCEEDED:
1838           t = "time exceeded";
1839           switch(dl->dl_icmp_code)
1840             {
1841             case ICMP6_TIME_EXCEED_TRANSIT:    c = "in trans"; break;
1842             case ICMP6_TIME_EXCEED_REASSEMBLY: c = "in reass"; break;
1843 
1844             default:
1845 	      snprintf(cbuf, sizeof(cbuf), "code %d", dl->dl_icmp_code);
1846 	      c = cbuf;
1847 	      break;
1848             }
1849           break;
1850 
1851 	case ICMP6_PACKET_TOO_BIG:
1852 	  snprintf(tbuf, sizeof(tbuf), "need frag %d", dl->dl_icmp_nhmtu);
1853 	  t = tbuf;
1854 	  break;
1855 
1856 	case ICMP6_ECHO_REPLY:
1857 	  t = "echo reply";
1858 	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
1859 		   dl->dl_icmp_id, dl->dl_icmp_seq);
1860 	  c = cbuf;
1861 	  break;
1862         }
1863     }
1864 
1865   if(t == NULL)
1866     {
1867       snprintf(icmp, sizeof(icmp), "icmp %d code %d",
1868 	       dl->dl_icmp_type, dl->dl_icmp_code);
1869     }
1870   else if(c == NULL)
1871     {
1872       snprintf(icmp, sizeof(icmp), "icmp %s", t);
1873     }
1874   else
1875     {
1876       snprintf(icmp, sizeof(icmp), "icmp %s %s", t, c);
1877     }
1878 
1879   if(dl->dl_icmp_ip_dst != NULL)
1880     {
1881       if(dl->dl_af == AF_INET)
1882 	{
1883 	  addr_tostr(AF_INET, dl->dl_icmp_ip_dst, addr, sizeof(addr));
1884 	  snprintf(inner_ip, sizeof(inner_ip),
1885 		   " to %s size %d ttl %d tos 0x%02x ipid 0x%04x",
1886 		   addr, dl->dl_icmp_ip_size, dl->dl_icmp_ip_ttl,
1887 		   dl->dl_icmp_ip_tos, dl->dl_icmp_ip_id);
1888 	}
1889       else
1890 	{
1891 	  addr_tostr(AF_INET6, dl->dl_icmp_ip_dst, addr, sizeof(addr));
1892 	  snprintf(inner_ip, sizeof(inner_ip),
1893 		   " to %s size %d hlim %d flow 0x%05x", addr,
1894 		   dl->dl_icmp_ip_size, dl->dl_icmp_ip_hlim,
1895 		   dl->dl_icmp_ip_flow);
1896 	}
1897 
1898       switch(dl->dl_icmp_ip_proto)
1899 	{
1900 	case IPPROTO_UDP:
1901 	  snprintf(inner_transport, sizeof(inner_transport),
1902 		   " proto UDP sport %d dport %d sum 0x%04x",
1903 		   dl->dl_icmp_udp_sport, dl->dl_icmp_udp_dport,
1904 		   ntohs(dl->dl_icmp_udp_sum));
1905 	  break;
1906 
1907 	case IPPROTO_ICMP:
1908 	case IPPROTO_ICMPV6:
1909 	  snprintf(inner_transport, sizeof(inner_transport),
1910 		   " proto ICMP type %d code %d id %04x seq %d",
1911 		   dl->dl_icmp_icmp_type, dl->dl_icmp_icmp_code,
1912 		   dl->dl_icmp_icmp_id, dl->dl_icmp_icmp_seq);
1913 	  break;
1914 
1915 	case IPPROTO_TCP:
1916 	  snprintf(inner_transport, sizeof(inner_transport),
1917 		   " proto TCP sport %d dport %d seq %08x",
1918 		   dl->dl_icmp_tcp_sport, dl->dl_icmp_tcp_dport,
1919 		   dl->dl_icmp_tcp_seq);
1920 	  break;
1921 
1922 	default:
1923 	  inner_transport[0] = '\0';
1924 	  break;
1925 	}
1926     }
1927   else
1928     {
1929       inner_ip[0] = '\0';
1930       inner_transport[0] = '\0';
1931     }
1932 
1933   scamper_debug(NULL, "%s %s%s%s", ip, icmp, inner_ip, inner_transport);
1934   return;
1935 }
1936 #endif
1937 
1938 /*
1939  * dl_read_cb
1940  *
1941  * this function is called by scamper_fds when a BPF fd fires as being
1942  * available to read from.
1943  */
1944 void scamper_dl_read_cb(const int fd, void *param)
1945 {
1946   assert(param != NULL);
1947 
1948 #if defined(HAVE_BPF)
1949   dl_bpf_read(fd, (scamper_dl_t *)param);
1950 #elif defined(__linux__)
1951   dl_linux_read(fd, (scamper_dl_t *)param);
1952 #elif defined(HAVE_DLPI)
1953   dl_dlpi_read(fd, (scamper_dl_t *)param);
1954 #endif
1955 
1956   return;
1957 }
1958 
1959 void scamper_dl_state_free(scamper_dl_t *dl)
1960 {
1961   assert(dl != NULL);
1962   free(dl);
1963   return;
1964 }
1965 
1966 /*
1967  * scamper_dl_state_alloc
1968  *
1969  * given the scamper_fd_t supplied, initialise the file descriptor and do
1970  * initial setup tasks, then compile and set a filter to pick up the packets
1971  * scamper is responsible for transmitting.
1972  */
1973 scamper_dl_t *scamper_dl_state_alloc(scamper_fd_t *fdn)
1974 {
1975   scamper_dl_t *dl = NULL;
1976 
1977   if((dl = malloc_zero(sizeof(scamper_dl_t))) == NULL)
1978     {
1979       printerror(__func__, "malloc node failed");
1980       goto err;
1981     }
1982   dl->fdn = fdn;
1983 
1984 #if defined(HAVE_BPF)
1985   if(dl_bpf_node_init(fdn, dl) == -1)
1986 #elif defined(__linux__)
1987   if(dl_linux_node_init(fdn, dl) == -1)
1988 #elif defined(HAVE_DLPI)
1989   if(dl_dlpi_node_init(fdn, dl) == -1)
1990 #endif
1991     {
1992       goto err;
1993     }
1994 
1995 #if defined(HAVE_BPF_FILTER)
1996   dl_filter(dl);
1997 #endif
1998 
1999   return dl;
2000 
2001  err:
2002   scamper_dl_state_free(dl);
2003   return NULL;
2004 }
2005 
2006 int scamper_dl_tx(const scamper_dl_t *node,
2007 		  const uint8_t *pkt, const size_t len)
2008 {
2009 #if defined(HAVE_BPF)
2010   if(dl_bpf_tx(node, pkt, len) == -1)
2011 #elif defined(__linux__)
2012   if(dl_linux_tx(node, pkt, len) == -1)
2013 #elif defined(HAVE_DLPI)
2014   if(dl_dlpi_tx(node, pkt, len) == -1)
2015 #endif
2016     {
2017       return -1;
2018     }
2019 
2020   return 0;
2021 }
2022 
2023 int scamper_dl_tx_type(scamper_dl_t *dl)
2024 {
2025   return dl->tx_type;
2026 }
2027 
2028 void scamper_dl_close(int fd)
2029 {
2030 #ifndef _WIN32
2031   close(fd);
2032 #endif
2033   return;
2034 }
2035 
2036 /*
2037  * scamper_dl_open_fd
2038  *
2039  * routine to actually open a datalink.  called by scamper_dl_open below,
2040  * as well as by the privsep code.
2041  */
2042 int scamper_dl_open_fd(const int ifindex)
2043 {
2044 #if defined(HAVE_BPF)
2045   return dl_bpf_open(ifindex);
2046 #elif defined(__linux__)
2047   return dl_linux_open(ifindex);
2048 #elif defined(HAVE_DLPI)
2049   return dl_dlpi_open(ifindex);
2050 #elif defined(_WIN32)
2051   return -1;
2052 #endif
2053 }
2054 
2055 /*
2056  * scamper_dl_open
2057  *
2058  * return a file descriptor for the datalink for the interface specified.
2059  * use privilege separation if required, otherwise open fd directly.
2060  */
2061 int scamper_dl_open(const int ifindex)
2062 {
2063   int fd;
2064 
2065 #if defined(WITHOUT_PRIVSEP)
2066   if((fd = scamper_dl_open_fd(ifindex)) == -1)
2067 #else
2068   if((fd = scamper_privsep_open_datalink(ifindex)) == -1)
2069 #endif
2070     {
2071       scamper_debug(__func__, "could not open ifindex %d", ifindex);
2072       return -1;
2073     }
2074 
2075   return fd;
2076 }
2077 
2078 void scamper_dl_cleanup()
2079 {
2080   if(readbuf != NULL)
2081     {
2082       free(readbuf);
2083       readbuf = NULL;
2084     }
2085 
2086   return;
2087 }
2088 
2089 int scamper_dl_init()
2090 {
2091 #if defined(HAVE_BPF)
2092   if(dl_bpf_init() == -1)
2093     {
2094       return -1;
2095     }
2096 #elif defined(__linux__)
2097   readbuf_len = 128;
2098   if((readbuf = malloc_zero(readbuf_len)) == NULL)
2099     {
2100       printerror(__func__, "could not malloc readbuf");
2101       readbuf_len = 0;
2102       return -1;
2103     }
2104 #elif defined(HAVE_DLPI)
2105   readbuf_len = 65536; /* magic obtained from pcap-dlpi.c */
2106   if((readbuf = malloc_zero(readbuf_len)) == NULL)
2107     {
2108       printerror(__func__, "could not malloc readbuf");
2109       readbuf_len = 0;
2110       return -1;
2111     }
2112 #endif
2113 
2114   return 0;
2115 }
2116