1 #include <libfb/fb_lib.h>
2 #include <libfb/fblib_ver.h>
3 #ifdef HAVE_STDLIB_H
4 # include <stdlib.h>
5 #endif
6 
7 #ifdef HAVE_UNISTD_H
8 # include <unistd.h>
9 #endif
10 
11 #ifdef HAVE_TIME_H
12 # include <time.h>
13 #endif
14 
15 /** @file fb_lib.c
16  * @author Brett Carrington
17  *
18  * @brief Most general library functions and all UDP transmission and
19  * reception functions
20  *
21  *
22  * @mainpage The foneBRIDGE library
23  *
24  *  The libfb library provides a comprehensive package for configuring
25  * and querying foneBRIDGE-based hardware devices over UDP and raw
26  * Ethernet. The library tracks the context of individual devices and
27  * handles all connections and data transmission using libnet and
28  * libpcap.
29  *
30  * The library is reentrant in the sense that different context
31  * pointers (devices) cannot effect each other. Each device must
32  * obtain a unique context using libfb_init() and then a connection to
33  * the device must be established with libfb_connect(). Multiple
34  * contexts to the same device produced undefined behavior.
35  *
36  */
37 
38 /************ Prototypes and Constants ***************/
39 static int set_filter (libfb_t * f, bpf_u_int32 mask);
40 
41 /** Valid configuations for longhaul LBOs*/
42 const unsigned char longlbo[MAX_LONGLBO] = {
43   PULS_LBO0,
44   PULS_LBO1,
45   PULS_LBO2,
46   PULS_LBO3
47 };
48 
49 /** Valid configuations for shorthaul LBOs*/
50 const unsigned char shortlbo[MAX_SHORTLBO] = {
51   PULS_133,
52   PULS_266,
53   PULS_399,
54   PULS_533,
55   PULS_655
56 };
57 
58 /** Table of libfb error strings */
59 const char *fberrstr[] = {
60   "Success",
61   "Try Again (Would Block)",
62   "Timed Out",
63   "Check System Errno",
64   "Invalid Argument",
65   "Invalid Bytecount",
66   "Exceeded System Maximum or Limit"
67 };
68 
69 /** Table of DOOF error strings (from the device) */
70 const char *dooferrstr[] = {
71   "Success",
72   "Failed CRC",
73   "No Memory Available",
74   "Invalid Command",
75   "Out of Bounds",
76   "No Device Present",
77   "Bad Packet Length",
78   "Bad Parameter"
79 };
80 
81 /************ Setup Functions ***************/
82 
83 /** @brief Print version information to stdout */
84 void
libfb_printver()85 libfb_printver ()
86 {
87   printf ("libfb Version %s, Build %d\n", FBLIB_VER, FBLIB_BUILD_NUM);
88 }
89 
90 /** @brief Library initalization routine
91  *
92  * This sets up the library to begin operation with a device. It
93  * returns the context pointer needed for almost all operations.
94  *
95  * @param device the name of the ethernet device if raw ethernet is used, otherwise NULL
96  * @param ethernet one of LIBFB_ETHERNET_OFF or LIBFB_ETHERNET_ON
97  * @param errstr A buffer of at least length LIBFB_ERRBUF_SIZE to store an error message
98  * @return The initalized context pointer, or NULL is an error occurs
99  */
100 libfb_t *
libfb_init(char * device,int ethernet,char * errstr)101 libfb_init (char *device, int ethernet, char *errstr)
102 {
103   libfb_t *f;
104 
105   bpf_u_int32 mask;		/* The netmask of our sniffing device */
106   bpf_u_int32 net;		/* The IP of our sniffing device */
107 
108   f = malloc (sizeof (libfb_t));
109   if (f == NULL)
110     {
111       strncpy (errstr, "Fatal error, could not allocate memory!\n",
112 	       LIBFB_ERRBUF_SIZE);
113       return NULL;
114     }
115 
116   memset (f, 0, sizeof (libfb_t));
117 
118   f->udp_socket = -1;
119 
120   if ((f->ether_on = ethernet) == LIBFB_ETHERNET_ON)
121     {
122 
123       if (device == NULL)
124 	{
125 	  strncpy (errstr, "Fatal error, no device specified!\n",
126 		   LIBFB_ERRBUF_SIZE);
127 	  goto init_error_out_1;
128 
129 	}
130 
131       f->s_mac = get_local_mac (device);
132       if (f->s_mac == NULL)
133 	{
134 	  strncpy (errstr, "Unable to lookup local MAC address!\n",
135 		   LIBFB_ERRBUF_SIZE);
136 	  goto init_error_out_1;
137 	}
138 
139       f->l = libnet_init (LIBNET_LINK, device, errstr);
140       if (f->l == NULL)
141 	goto init_error_out_2;	/* libnet/libpcap will fill out errstr from here on in */
142 
143       /* look up netmask */
144       if (pcap_lookupnet (device, &net, &mask, errstr) == -1)
145 	{
146 	  fprintf (stderr,
147 		   "[Warning] Can't get netmask for device %s\n", device);
148 	  net = 0;
149 	  mask = 0;
150 	}
151 
152       /* open pcap */
153       f->p = pcap_open_live (device, 512, 0, 0, errstr);
154       if (f->p == NULL)
155 	goto init_error_out_3;
156 
157       /* set up pcap filter */
158       if (set_filter (f, mask) == -1)
159 	{
160 	  strncpy (errstr, pcap_geterr (f->p), LIBFB_ERRBUF_SIZE);
161 	  goto init_error_out_4;
162 	}
163     }				/* end of ethernet enabling functions */
164 
165   f->crc_en = 0;
166   f->device = device;
167   return f;
168 
169   /* Error handling, free up things we've allocated */
170 init_error_out_4:
171   pcap_close (f->p);
172 init_error_out_3:
173   libnet_destroy (f->l);
174 init_error_out_2:
175   free (f->s_mac);
176 init_error_out_1:
177   free (f);
178   return NULL;
179 }
180 
181 
182 /** @brief Connect to a device via UDP sockets
183  *
184  * This is usually the first operation done after obtaining the
185  * context pointer with libfb_init. Communication with the device via
186  * UDP is not possible until this connection is established.
187  *
188  * @param f the device context pointer
189  * @param host null-terminated string representing the hostname (or IP address) of the device
190  * @param port the UDP port to use, historically 1024 has been used for foneBRIDGE-type devices
191  * @return an fblib_err error code, or FBLIB_ESUCCESS if successfully connected
192  */
193 fblib_err
libfb_connect(libfb_t * f,const char * host,int port)194 libfb_connect (libfb_t * f, const char *host, int port)
195 {
196   struct hostent *hostPtr = NULL;
197   struct sockaddr_in dSock = { 0 };
198 
199   f->udp_socket = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
200   if (f->udp_socket == -1)
201     return FBLIB_EERRNO;
202 
203   hostPtr = gethostbyname (host);
204   if (hostPtr == NULL)
205     {
206       hostPtr = gethostbyaddr (host, strlen (host), AF_INET);
207       if (hostPtr == NULL)
208 	return FBLIB_EHERRNO;
209     }
210 
211   dSock.sin_family = AF_INET;
212   dSock.sin_port = htons (port);
213   memcpy (&dSock.sin_addr, hostPtr->h_addr, hostPtr->h_length);
214 
215   if ((connect (f->udp_socket, (struct sockaddr *) &dSock, sizeof (dSock))) ==
216       -1)
217     return FBLIB_EERRNO;
218 
219   f->connected = 1;
220   return FBLIB_ESUCCESS;
221 }
222 
223 /** \brief Internal function to set up libpcap filter for 0xD00F packets
224  *
225  * \param f must be a libfb_t context with a valid pcap context
226  * \param mask the netmask on the interface the context operates on
227  * \return 0 on success, -1 if a failure occured
228  */
229 static int
set_filter(libfb_t * f,bpf_u_int32 mask)230 set_filter (libfb_t * f, bpf_u_int32 mask)
231 {
232   struct bpf_program filter;
233   char m_str[] = "00:00:00:00:00:00";
234   char filterstr[128];
235 
236   strcpy (filterstr, "ether proto 0xd00f and ether dst ");
237   sprintf (m_str, "%02X:%02X:%02X:%02X:%02X:%02X",
238 	   f->s_mac[0], f->s_mac[1], f->s_mac[2],
239 	   f->s_mac[3], f->s_mac[4], f->s_mac[5]);
240 
241   if (pcap_compile (f->p, &filter, strcat (filterstr, m_str), 0, mask) == -1)
242     return -1;
243 
244   if (pcap_setfilter (f->p, &filter) == -1)
245     return -1;
246 
247   return 0;
248 }
249 
250 
251 /** @brief Set reference times for printing date information
252  *
253  * This must be called before the libfb_get-ctime and
254  * libfb_get_systime functions are used.
255  *
256  * @param f the device context
257  */
258 void
set_reftime(libfb_t * f)259 set_reftime (libfb_t * f)
260 {
261   struct tm time_info;
262 
263   /* Set ref. time to Jan 1st 2000 */
264   memset (&time_info, 0, sizeof (struct tm));
265   time_info.tm_mday = 1;
266   time_info.tm_mon = 0;
267   time_info.tm_year = 100;
268   f->ref_ctime = mktime (&time_info);
269 
270   /* Set the reference for the SYSID timestamp */
271   time_info.tm_year = 70;
272   f->sysid_ctime = mktime (&time_info);
273 }
274 
275 /**
276  *  @brief Get the flash date information
277  *  @param f the device context
278  *  @return the flash date
279  */
280 inline time_t
libfb_get_ctime(libfb_t * f)281 libfb_get_ctime (libfb_t * f)
282 {
283   return f->ref_ctime;
284 }
285 
286 /**
287  * @brief get the sysid time stamp
288  * @param f the device context
289  * @return the sysid time stamp
290  */
291 inline time_t
libfb_get_systime(libfb_t * f)292 libfb_get_systime (libfb_t * f)
293 {
294   return f->sysid_ctime;
295 }
296 
297 /************ Shutdown Functions ***************/
298 
299 /** @brief free resources used by the library
300  *
301  * @param f the context owning the resources
302  * @return always succeeds with FBLIB_ESUCCESS
303  */
304 fblib_err
libfb_destroy(libfb_t * f)305 libfb_destroy (libfb_t * f)
306 {
307   if (f)
308     {
309       if (f->connected)
310 	close (f->udp_socket);
311 
312       if (f->p)
313 	pcap_close (f->p);
314 
315       if (f->l)
316 	libnet_destroy (f->l);
317 
318       if (f->s_mac)
319 	free (f->s_mac);
320 
321       free (f);
322     }
323 
324   return FBLIB_ESUCCESS;
325 }
326 
327 
328 
329 /************ FB Query Functions ***************/
330 /** @brief print the device static information to stream
331  *
332  * @param f the device context
333  * @param stream the output stream (i.e. stdout, stderr...)
334  * @param packet_in the DOOF_STATIC_INFO data structure containing the information to display
335  */
336 void
fprint_static_info(libfb_t * f,FILE * stream,DOOF_STATIC_INFO * packet_in)337 fprint_static_info (libfb_t * f, FILE * stream, DOOF_STATIC_INFO * packet_in)
338 {
339   struct tm *time_info = malloc (sizeof (struct tm));
340   time_t calendar_time;
341   int x;
342 
343   set_reftime (f);
344 
345   fprintf (stream, "SW ver: %s\n", packet_in->sw_ver);
346   fprintf (stream, "SW Compile date: %s\n", packet_in->sw_compile_date);
347   fprintf (stream, "Build number: %d\n", packet_in->build_num);
348   fprintf (stream, "FB core ver sig: 0x%X\n", packet_in->fb_core_version);
349   fprintf (stream, "Spans: %d Devices: %d MACs: %d\n", packet_in->spans,
350 	   packet_in->devices, packet_in->mac_num);
351   fprintf (stream, "EPCS Blocks: %d\n", packet_in->epcs_blocks);
352   fprintf (stream, "EPCS Block size: 0x%X (%d KB)\n",
353 	   packet_in->epcs_block_size, packet_in->epcs_block_size / 1024);
354   fprintf (stream, "EPCS Region size: 0x%X (%d KB)\n",
355 	   packet_in->epcs_region_size, packet_in->epcs_region_size / 1024);
356   fprintf (stream, "\nStored config data:\n");
357   fprintf (stream, "--------------------\n");
358   for (x=0; x<packet_in->mac_num; x++) {
359 	  fprintf (stream, "MAC[%d]: ", x);
360 	  fprint_mac (stream, packet_in->epcs_config.mac_addr);
361 	  packet_in->epcs_config.mac_addr[5]++;
362 	  fprintf (stream, "IP[%d]: ", x);
363 	  fprint_ip (stream, packet_in->epcs_config.ip_address[x]);
364   }
365   fprintf (stream, "Serial: %s\n", packet_in->epcs_config.snumber);
366   fprintf (stream, "CFG Flags: 0x%X (%s)\n",
367 	   packet_in->epcs_config.cfg_flags,
368 	   packet_in->epcs_config.cfg_flags & (1 << 0) ? "IEC" : "FB2");
369   calendar_time = packet_in->epcs_config.mfg_date + libfb_get_ctime (f);
370   time_info = localtime (&calendar_time);
371   fprintf (stream, "Flash Date: %d (%d/%d/%d %d:%d:%d)\n",
372 	   (int) calendar_time, time_info->tm_mon + 1, time_info->tm_mday,
373 	   time_info->tm_year + 1900, time_info->tm_hour, time_info->tm_min,
374 	   time_info->tm_sec);
375   fprintf (stream, "CRC: 0x%X\n", packet_in->epcs_config.crc16);
376   fprintf (stream, "SYSID CRC: 0x%X\n", packet_in->fpga_sysid);
377   calendar_time = packet_in->fpga_timestamp + libfb_get_systime (f);
378 
379   time_info = localtime (&calendar_time);
380   fprintf (stream, "SYSID Timestamp: 0x%X (%d/%d/%d %d:%d:%d)\n",
381 	   packet_in->fpga_timestamp,
382 	   time_info->tm_mon + 1, time_info->tm_mday,
383 	   time_info->tm_year + 1900, time_info->tm_hour, time_info->tm_min,
384 	   time_info->tm_sec);
385   fprintf (stream, "Attempted boots: %d\n",
386 	   packet_in->epcs_config.attempted_boots);
387   fprintf (stream, "GPAK File Length: %d bytes\n",
388 	   packet_in->epcs_config.gpak_len);
389   fprintf (stream, "\nDSP Parameters\n-----------------\n");
390   fprintf (stream, "Active/Max channels: %d/%d\n",
391 	   packet_in->gpak_config.active_channels,
392 	   packet_in->gpak_config.max_channels);
393   fprintf (stream, "BIST: %d Num EC: %d\n", packet_in->gpak_config.bist,
394 	   packet_in->gpak_config.num_ec);
395   fprintf (stream, "Stream0: Max channels: %d Supported channels: %d\n",
396 	   packet_in->gpak_config.stream_slots[0],
397 	   packet_in->gpak_config.stream_supported_slots[0]);
398   fprintf (stream, "Stream1: Max channels: %d Supported channels: %d\n",
399 	   packet_in->gpak_config.stream_slots[1],
400 	   packet_in->gpak_config.stream_supported_slots[1]);
401   fprintf (stream, "GPAK VerID: 0x%X\n", packet_in->gpak_config.ver);
402 }
403 
404 /** @brief print the device static information to stdout
405  *
406  * @param f the device context
407  * @param packet_in the DOOF_STATIC_INFO data structure containing the information to display
408  */
409 void
print_static_info(libfb_t * f,DOOF_STATIC_INFO * packet_in)410 print_static_info (libfb_t * f, DOOF_STATIC_INFO * packet_in)
411 {
412   fprint_static_info (f, stdout, packet_in);
413 }
414 
415 /** @brief get the DOOF_STATIC_INFO information from a device using raw Ethernet
416  *
417  * @param f the device context
418  * @param dest_mac the destination MAC address
419  * @param doof_info pointer to location to store the DOOF_STATIC_INFO
420  * @return returns the length of the DOOF response
421  */
422 int
get_static_info(libfb_t * f,unsigned char * dest_mac,DOOF_STATIC_INFO * doof_info)423 get_static_info (libfb_t * f, unsigned char *dest_mac,
424 		 DOOF_STATIC_INFO * doof_info)
425 {
426   return get_epcs_pointer (f, dest_mac, doof_info);
427 }
428 
429 /** @brief workhorse function for get_static_info
430  *
431  *  @param f the device context
432  *  @param dest_mac the destination MAC address
433  *  @param ptr pointer to a buffer to store the DOOF_STATIC_INFO in
434  *  @return returns the length of the DOOF response
435  */
436 int
get_epcs_pointer(libfb_t * f,unsigned char * dest_mac,DOOF_STATIC_INFO * ptr)437 get_epcs_pointer (libfb_t * f, unsigned char *dest_mac,
438 		  DOOF_STATIC_INFO * ptr)
439 {
440   int res;
441   unsigned char recv_buf[1500];
442 
443   res =
444     doof_txrx (f, dest_mac, NULL, DOOF_CMD_GET_STATIC_INFO, 0, 0, recv_buf);
445 
446   if (res < 0)
447     return res;
448 
449   if (res != sizeof (DOOF_STATIC_INFO))
450     {
451       printf ("get_static_info: Incorrent byte-length received (%d)\n", res);
452       return -DOOF_RESP_BADSIZE;
453     }
454 
455 
456   memcpy ((unsigned char *) ptr, recv_buf + DOOF_PL_OFF + 14,
457 	  sizeof (DOOF_STATIC_INFO));
458 
459   return 0;
460 }
461 
462 /************ End FB Query Functions ***********/
463 
464 /********************** UDP Functions *******************/
465 /** @brief the modern way to get the DOOF_STATIC_INFO information
466  *
467  * @param f the device context
468  * @param dsi location to store the DOOF_STATIC_INFO information in
469  * @return an fblib_err representing success or failure
470  */
471 fblib_err
udp_get_static_info(libfb_t * f,DOOF_STATIC_INFO * dsi)472 udp_get_static_info (libfb_t * f, DOOF_STATIC_INFO * dsi)
473 {
474   unsigned char buffer[1500];
475   ssize_t status;
476   fblib_err ret;
477   /* getinfo */
478   buffer[0] = 0;
479   buffer[1] = DOOF_CMD_GET_STATIC_INFO;
480 
481   /* write packet */
482   if (!udp_ready_write (f))
483     return FBLIB_EAGAIN;
484 
485   status = write (f->udp_socket, buffer, 2);
486   if (status == -1)
487     return FBLIB_EERRNO;
488 
489   /* read back */
490   ret = poll_for_newpkt (f);
491   if (ret != FBLIB_ESUCCESS)
492     return ret;
493 
494   status = read (f->udp_socket, buffer, sizeof (buffer));
495 
496   /* Check length */
497   if (status != (2 + sizeof (DOOF_STATIC_INFO)))
498     {
499       return -DOOF_RESP_BADSIZE;
500     }
501   /* Length is correct */
502   memcpy ((void *) dsi, buffer + 2, sizeof (DOOF_STATIC_INFO));
503 
504   return FBLIB_ESUCCESS;
505 }
506 
507 /** @brief Execute a DOOF_CMD_READ_DSP command
508  *
509  * @attention This needs better documentation.
510  *
511  * @param f the device context
512  * @param address the DSP address to read
513  * @param len the payload length?
514  * @param intbuf memory location to store response
515  * @return an fblib_err representing success or failure
516  */
517 fblib_err
readdsp(libfb_t * f,unsigned int address,size_t len,unsigned int * intbuf)518 readdsp (libfb_t * f, unsigned int address, size_t len, unsigned int *intbuf)
519 {
520   unsigned char buffer[1500];
521   DOOF_BLK *doof_blk;
522   ssize_t status;
523   fblib_err ret;
524 
525   /* First token is cmd */
526   buffer[0] = 0;
527   buffer[1] = DOOF_CMD_READ_DSP;
528   doof_blk = (DOOF_BLK *) (buffer + 2);
529   doof_blk->addr = address;
530   doof_blk->len = len;
531 
532   if (len == 0)
533     return FBLIB_EINVAL;
534 
535 
536   if (!udp_ready_write (f))
537     return FBLIB_EAGAIN;
538 
539   write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2);
540 
541   /* read back */
542   ret = poll_for_newpkt (f);
543   if (ret != FBLIB_ESUCCESS)
544     return ret;
545 
546   status = read (f->udp_socket, buffer, sizeof (buffer));
547 
548   if (buffer[1])
549     {
550       printf ("Error code reported from device: %d\n", buffer[1]);
551       return -buffer[1];
552     }
553 
554   if (status != (len * 4 + sizeof (DOOF_BLK) + 2))
555     {
556       printf ("Error in byte-count received\n");
557       return -DOOF_RESP_BADSIZE;
558     }
559   memcpy ((void *) intbuf, (void *) buffer + sizeof (DOOF_BLK) + 2, len * 4);
560   return 0;
561 }
562 
563 /** @brief Write to a DSP address
564  *
565  * @attention This needs better documentation.
566  *
567  * @param f the device context
568  * @param address the DSP address to write to
569  * @param len the payload length
570  * @param intbuf memory location of buffer
571  * @return an fblib_err representing success or failure
572  */
573 fblib_err
writedsp(libfb_t * f,unsigned int address,size_t len,unsigned int * intbuf)574 writedsp (libfb_t * f, unsigned int address, size_t len, unsigned int *intbuf)
575 {
576   unsigned char buffer[1500];
577   unsigned int *intptr;
578   ssize_t status;
579   fblib_err ret;
580 
581   DOOF_BLK *doof_blk;
582   buffer[0] = 0;
583   buffer[1] = DOOF_CMD_WRITE_DSP;
584   doof_blk = (DOOF_BLK *) (buffer + 2);
585 
586   doof_blk->addr = address;
587   doof_blk->len = len;
588 
589   intptr = (unsigned int *) (buffer + sizeof (DOOF_BLK) + 2);
590   memcpy ((void *) intptr, intbuf, len * 4);
591   write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2 + len * 4);
592 
593   /* read back */
594   ret = poll_for_newpkt (f);
595   if (ret != FBLIB_ESUCCESS)
596     return ret;
597 
598   status = read (f->udp_socket, buffer, sizeof (buffer));
599 
600   if (buffer[1])
601     {
602       fprintf (stderr, "Error code reported from device: %d\n", buffer[1]);
603       return -buffer[1];
604     }
605 
606   if (status != (sizeof (DOOF_BLK) + 2))
607     return FBLIB_EBYTECOUNT;
608 
609   return FBLIB_ESUCCESS;
610 }
611 
612 
613 /** @brief Set the echo canceller channel types for the entire DSP
614  *
615  * We only set one group of types at a time, mask represents which channels get those types.
616  *
617  * @param f the device context
618  * @param type the DSP channel type value
619  * @param mask array of masks, 32 bits (one bit per channel) for each span. Each array index is one span.
620  * @return an fblib_err representing success or failure
621  */
622 fblib_err
ec_set_chantype(libfb_t * f,unsigned char type,uint32_t * mask)623 ec_set_chantype (libfb_t * f, unsigned char type, uint32_t * mask)
624 {
625   unsigned char buffer[1500];
626   unsigned char *charptr;
627   ssize_t status;
628   unsigned int x;
629   fblib_err ret;
630   buffer[0] = type;
631   buffer[1] = DOOF_CMD_EC_CHAN_TYPE;
632   charptr = buffer + 2;
633 
634   for (x = 0; x < 16; x++)
635     {
636       *charptr++ = (mask[x / 4] >> ((x % 4) * 8)) & 0xff;
637     }
638 
639   if (!udp_ready_write (f))
640     return FBLIB_EAGAIN;
641 
642   status = write (f->udp_socket, buffer, 4 * 4 + 2);
643   if (status == -1)
644     return FBLIB_EERRNO;
645 
646   /* read back */
647   ret = poll_for_newpkt (f);
648   if (ret != FBLIB_ESUCCESS)
649     return ret;
650 
651   status = read (f->udp_socket, buffer, sizeof (buffer));
652   if (buffer[1])
653     {
654       printf ("Error code reported from device: %d\n", buffer[1]);
655       return -buffer[1];
656     }
657 
658   if (status != (2))
659     {
660       return FBLIB_EBYTECOUNT;
661     }
662   return FBLIB_ESUCCESS;
663 }
664 
665 /** @brief Send a custom DOOF command over UDP
666  *
667  * @param f the device context
668  * @param cmd the DOOF command to send
669  * @param param optional parameters to the DOOF command
670  * @param buf payload to send with the command
671  * @param len the length of the payload
672  * @return an fblib_err representing success or failure
673  */
674 fblib_err
custom_cmd(libfb_t * f,unsigned char cmd,unsigned char param,char * buf,size_t len)675 custom_cmd (libfb_t * f, unsigned char cmd, unsigned char param, char *buf,
676 	    size_t len)
677 {
678   unsigned char buffer[1500];
679   ssize_t status;
680   fblib_err ret;
681 
682   if (!udp_ready_write (f))
683     return FBLIB_EAGAIN;
684 
685   buffer[0] = param;
686   buffer[1] = cmd;
687   memcpy ((void *) buffer + 2, buf, len);
688 
689   status = write (f->udp_socket, buffer, 2 + len);
690   if (status == -1)
691     return FBLIB_EERRNO;
692 
693   /* read back */
694   ret = poll_for_newpkt (f);
695   if (ret != FBLIB_ESUCCESS)
696     return ret;
697 
698   status = read (f->udp_socket, buffer, sizeof (buffer));
699   if (status != (2))
700     {
701       printf ("Error in byte-count received\n");
702       return -DOOF_RESP_BADSIZE;
703     }
704 
705 #ifdef DEBUG
706   fprintf (stderr, "{custom_cmd 0x%02X param 0x%02X resp 0x%02X}\n",
707 	   cmd, param, buffer[1]);
708 #endif
709 
710   return -buffer[1];
711 }
712 
713 /** @brief Send a custom DOOF command over UDP and block until a reply is received
714  *
715  * @param f the device context
716  * @param cmd the DOOF command to send
717  * @param param optional parameters to the DOOF command
718  * @param buf payload to send with the command
719  * @param len the length of the payload
720  * @param rbuf location to store the reply
721  * @param rlen the expected reply length
722  * @return an fblib_err representing success or failure
723  */
724 fblib_err
custom_cmd_reply(libfb_t * f,unsigned char cmd,unsigned char param,char * buf,size_t len,char * rbuf,size_t rlen)725 custom_cmd_reply (libfb_t * f, unsigned char cmd, unsigned char param,
726 		  char *buf, size_t len, char *rbuf, size_t rlen)
727 {
728   unsigned char buffer[1500];
729   ssize_t status;
730   fblib_err ret;
731 
732   if (!udp_ready_write (f))
733     return FBLIB_EAGAIN;
734 
735   buffer[0] = param;
736   buffer[1] = cmd;
737   memcpy ((void *) buffer + 2, buf, len);
738   status = write (f->udp_socket, buffer, 2 + len);
739 
740   if (status == -1)
741     return FBLIB_EERRNO;
742 
743   /* read back */
744   ret = poll_for_newpkt (f);
745   if (ret != FBLIB_ESUCCESS)
746     return ret;
747 
748   status = read (f->udp_socket, buffer, sizeof (buffer));
749   if (status != (rlen + 2))
750     {
751       printf ("Error in byte-count received\n");
752       return -DOOF_RESP_BADSIZE;
753     }
754   memcpy ((void *) rbuf, buffer + 2, rlen);
755 
756 #ifdef DEBUG
757   fprintf (stderr, "{custom_cmd_reply 0x%02X param 0x%02X resp 0x%02X}\n",
758 	   cmd, param, buffer[1]);
759 #endif
760 
761   return -buffer[1];
762 }
763 
764 
765 /** @brief Needs documentation! */
766 fblib_err
readmem32(libfb_t * f,unsigned int address,size_t len,uint32_t * intbuf)767 readmem32 (libfb_t * f, unsigned int address, size_t len, uint32_t * intbuf)
768 {
769   unsigned char buffer[1500];
770   DOOF_BLK *doof_blk;
771   ssize_t status;
772   fblib_err ret;
773 
774   /* First token is cmd */
775   buffer[0] = 2;		/* Param 2 is for 32-byte */
776   buffer[1] = DOOF_CMD_READ_MEM;
777   doof_blk = (DOOF_BLK *) (buffer + 2);
778 
779   doof_blk->addr = address;
780   doof_blk->len = len;
781 
782   if (len == 0)
783     return FBLIB_EINVAL;
784 
785   if (!udp_ready_write (f))
786     return FBLIB_EAGAIN;
787 
788   status = write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2);
789   if (status == -1)
790     return FBLIB_EERRNO;
791 
792   /* read back */
793   ret = poll_for_newpkt (f);
794   if (ret != FBLIB_ESUCCESS)
795     return ret;
796 
797   status = read (f->udp_socket, buffer, sizeof (buffer));
798 
799   if (buffer[1])
800     {
801       printf ("Error code reported from device: %d\n", buffer[1]);
802       return -buffer[1];
803     }
804 
805   if (status != (len * 4 + sizeof (DOOF_BLK) + 2))
806     return FBLIB_EBYTECOUNT;
807 
808   memcpy ((void *) intbuf, (void *) buffer + sizeof (DOOF_BLK) + 2, len * 4);
809   return FBLIB_ESUCCESS;
810 }
811 
812 
813 /** @brief Read arbitrary device memory address
814  *
815  * @param f the device context
816  * @param address the memory address to read
817  * @param len the length of the data to read
818  * @param charbuf location to store the result
819  * @return an fblib_err representing success or failure
820  */
821 fblib_err
readmem(libfb_t * f,unsigned int address,size_t len,char * charbuf)822 readmem (libfb_t * f, unsigned int address, size_t len, char *charbuf)
823 {
824   unsigned char buffer[1500];
825   DOOF_BLK *doof_blk;
826   ssize_t status;
827   fblib_err ret;
828 
829   /* First token is cmd */
830   buffer[0] = 0;
831   buffer[1] = DOOF_CMD_READ_MEM;
832   doof_blk = (DOOF_BLK *) (buffer + 2);
833 
834 
835   doof_blk->addr = address;
836   doof_blk->len = len;
837 
838   if (len == 0)
839     return FBLIB_EINVAL;
840 
841   if (!udp_ready_write (f))
842     return FBLIB_EAGAIN;
843 
844   status = write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2);
845   if (status == -1)
846     return FBLIB_EERRNO;
847 
848   /* read back */
849   ret = poll_for_newpkt (f);
850   if (ret != FBLIB_ESUCCESS)
851     return ret;
852 
853   status = read (f->udp_socket, buffer, sizeof (buffer));
854 
855   if (buffer[1])
856     {
857       printf ("Error code reported from device: %d\n", buffer[1]);
858       return -buffer[1];
859     }
860 
861   if (status != (len + sizeof (DOOF_BLK) + 2))
862     return FBLIB_EBYTECOUNT;
863 
864   memcpy ((void *) charbuf, (void *) buffer + sizeof (DOOF_BLK) + 2, len);
865   return FBLIB_ESUCCESS;
866 }
867 
868 /** @brief Update and then reset PMON counters/registers
869  *
870  *
871  * @param f the device context
872  * @param span the span on the transceiver to access, in the range 0 to 3
873  * @return an fblib_err representing success or failure
874  */
875 fblib_err
libfb_updat_pmon(libfb_t * f,uint8_t span)876 libfb_updat_pmon (libfb_t * f, uint8_t span)
877 {
878   fblib_err ret;
879 
880   /* Force a transition from 0 to 1 */
881   ret = writeidt (f, span, 0xC2, 0x0);
882   if (ret != FBLIB_ESUCCESS)
883     return ret;
884 
885   ret = writeidt (f, span, 0xC2, 0x2);
886   if (ret != FBLIB_ESUCCESS)
887     return ret;
888 
889   return FBLIB_ESUCCESS;
890 }
891 
892 /** @brief Read an IDT indirect PMON register
893  *
894  * Registers are 8-bit wide. Reading and companding two registers
895  * (like the LCV0/1 register as an example) is not supported. You must
896  * do this manually. UPDAT must also be sent manually via
897  * libfb_updat_pmon().
898  *
899  * @param f the device context
900  * @param span the span to read from
901  * @param address the register address to read
902  * @param data location to store 8-bit response
903  *
904  * @return an fblib_err representing success or failure
905  */
906 fblib_err
libfb_readidt_pmon(libfb_t * f,uint8_t span,uint8_t address,uint8_t * data)907 libfb_readidt_pmon (libfb_t * f, uint8_t span, uint8_t address,
908 		    uint8_t * data)
909 {
910   fblib_err ret;
911   uint8_t pmonaccess = (address & 0xF) | (((span % 2) & 0xF) << 5);
912   int devnum = 0;
913 
914   switch (span)
915     {
916     case 0:
917     case 1:
918       devnum = 0;
919       break;
920     case 2:
921     case 3:
922       devnum = 2;
923       break;
924     }
925 
926   /* Set ADDR and LINKSEL0 */
927   ret = writeidt (f, devnum, 0x00E, pmonaccess);
928   if (ret != FBLIB_ESUCCESS)
929     return ret;
930 
931   /* Read DAT */
932   ret = readidt (f, devnum, 0x00F, 1, (char *) data);
933   if (ret != FBLIB_ESUCCESS)
934     return ret;
935 
936   return FBLIB_ESUCCESS;
937 }
938 
939 /** @brief Write arbitrary transceiver register
940  *
941  * The address should be of the form 0xAB. The span parameter is used
942  * to expand the address into the IDT native register address form of
943  * 0xXAB where X is the correct span number on the targeted device.
944  *
945  * @param f the device context
946  * @param span the span we wish to write to
947  * @param address the register to write to
948  * @param data the 8-bit data to write
949  * @return an fblib_err representing success or failure
950  */
951 fblib_err
writeidt(libfb_t * f,unsigned char span,uint8_t address,uint8_t data)952 writeidt (libfb_t * f, unsigned char span, uint8_t address, uint8_t data)
953 {
954   uint8_t buffer[2];
955 
956   buffer[0] = address;
957   buffer[1] = data;
958 
959   return custom_cmd (f, DOOF_CMD_IDT_WRITE_REG, span, buffer, 2);
960 }
961 
962 /** @brief Read arbitrary transceiver memory address
963  *
964  * The address should be of the form 0xAB. The span parameter is used
965  * to expand the address into the IDT native register address form of
966  * 0xXAB where X is the correct span number on the targeted device.
967  *
968  * @param f the device context
969  * @param span the transceiver we wish to read from
970  * @param address the memory address to read
971  * @param len the length of the data to read
972  * @param charbuf location to store the result
973  * @return an fblib_err representing success or failure
974  */
975 fblib_err
readidt(libfb_t * f,unsigned char span,unsigned int address,size_t len,char * charbuf)976 readidt (libfb_t * f, unsigned char span, unsigned int address, size_t len,
977 	 char *charbuf)
978 {
979   unsigned char buffer[1500];
980   DOOF_BLK *doof_blk;
981   ssize_t status;
982   fblib_err ret;
983 
984   /* First token is cmd */
985   buffer[0] = span;
986   buffer[1] = DOOF_CMD_READ_IDT_REG;
987   doof_blk = (DOOF_BLK *) (buffer + 2);
988 
989   doof_blk->addr = address;
990   doof_blk->len = len;
991 
992   if (len == 0)
993     return FBLIB_EINVAL;
994 
995   if (!udp_ready_write (f))
996     return FBLIB_EAGAIN;
997 
998   status = write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2);
999   if (status == -1)
1000     return FBLIB_EERRNO;
1001 
1002   /* read back */
1003   ret = poll_for_newpkt (f);
1004   if (ret != FBLIB_ESUCCESS)
1005     return ret;
1006 
1007   status = read (f->udp_socket, buffer, sizeof (buffer));
1008 
1009   if (status >= 2 && buffer[1])
1010     {
1011       printf ("Error code reported from device: %d\n", buffer[1]);
1012       return -buffer[1];
1013     }
1014 
1015   if (status != (len + sizeof (DOOF_BLK) + 2))
1016     return FBLIB_EBYTECOUNT;
1017 
1018   memcpy ((void *) charbuf, (void *) buffer + sizeof (DOOF_BLK) + 2, len);
1019   return FBLIB_ESUCCESS;
1020 }
1021 
1022 /** @brief Get the GPAK_FLASH_PARMS information from a device
1023  *
1024  * @param f the device context
1025  * @param buf location to store the GPAK_FLASH_PARMS
1026  * @return an fblib_err representing success or failure
1027  */
1028 fblib_err
fblib_get_gpakparms(libfb_t * f,GPAK_FLASH_PARMS * buf)1029 fblib_get_gpakparms (libfb_t * f, GPAK_FLASH_PARMS * buf)
1030 {
1031   unsigned char buffer[1500];
1032   ssize_t status;
1033   fblib_err ret;
1034 
1035   if (buf == NULL)
1036     return FBLIB_EINVAL;
1037 
1038   /* First token is cmd */
1039   buffer[0] = 0;
1040   buffer[1] = DOOF_CMD_GET_GPAK_FLASH_PARMS;
1041 
1042   if (!udp_ready_write (f))
1043     return FBLIB_EAGAIN;
1044 
1045   write (f->udp_socket, buffer, 2);
1046 
1047   /* read back */
1048   ret = poll_for_newpkt (f);
1049   if (ret != FBLIB_ESUCCESS)
1050     return ret;
1051 
1052   status = read (f->udp_socket, buffer, sizeof (buffer));
1053 
1054   if (buffer[1])
1055     {
1056       printf ("Error code reported from device: %d\n", buffer[1]);
1057       return -buffer[1];
1058     }
1059 
1060   if (status != (sizeof (GPAK_FLASH_PARMS) + 2))
1061     return FBLIB_EBYTECOUNT;
1062 
1063   memcpy (buf, buffer + 2, sizeof (GPAK_FLASH_PARMS));
1064   return FBLIB_ESUCCESS;
1065 }
1066 
1067 /** @brief Read a SPI register
1068  *
1069  * @param f the device context
1070  * @param dev the SPI device address
1071  * @param address the memory address to read from the device, `dev'
1072  * @param len the length of data to read
1073  * @param charbuf location to store the result
1074  * @return an fblib_err representing success or failure
1075  */
1076 fblib_err
readspi(libfb_t * f,unsigned char dev,unsigned char address,size_t len,char * charbuf)1077 readspi (libfb_t * f, unsigned char dev, unsigned char address, size_t len,
1078 	 char *charbuf)
1079 {
1080   unsigned char buffer[1500];
1081   DOOF_BLK *doof_blk;
1082   ssize_t status;
1083   fblib_err ret;
1084 
1085   /* First token is cmd */
1086   buffer[0] = dev;
1087   buffer[1] = DOOF_CMD_SPI_READREG;
1088   doof_blk = (DOOF_BLK *) (buffer + 2);
1089 
1090   doof_blk->addr = address;
1091   doof_blk->len = len;
1092 
1093   if (len == 0)
1094     return FBLIB_EINVAL;
1095 
1096   if (!udp_ready_write (f))
1097     return FBLIB_EAGAIN;
1098 
1099   status = write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2);
1100   if (status == -1)
1101     return FBLIB_EERRNO;
1102 
1103   /* read back */
1104   ret = poll_for_newpkt (f);
1105   if (ret != FBLIB_ESUCCESS)
1106     return ret;
1107 
1108   status = read (f->udp_socket, buffer, sizeof (buffer));
1109 
1110   if (buffer[1])
1111     {
1112       printf ("Error code reported from device: %d\n", buffer[1]);
1113       return -buffer[1];
1114     }
1115 
1116   if (status != (len + sizeof (DOOF_BLK) + 2))
1117     return FBLIB_EBYTECOUNT;
1118 
1119   memcpy ((void *) charbuf, (void *) buffer + sizeof (DOOF_BLK) + 2, len);
1120   return FBLIB_ESUCCESS;
1121 }
1122 
1123 /** @brief Write to a SPI register
1124  *
1125  * @param f the device context
1126  * @param dev the SPI device address
1127  * @param address the memory address to write to the device, `dev'
1128  * @param len the length of data to write
1129  * @param charbuf location to data payload
1130  * @return an fblib_err representing success or failure
1131  */
1132 fblib_err
writespi(libfb_t * f,unsigned char dev,unsigned char address,size_t len,char * charbuf)1133 writespi (libfb_t * f, unsigned char dev, unsigned char address, size_t len,
1134 	  char *charbuf)
1135 {
1136   DOOF_BLK *doof_blk;
1137   unsigned char buffer[1500];
1138   unsigned char *charptr;
1139   ssize_t status;
1140   fblib_err ret;
1141 
1142 
1143   buffer[0] = dev;
1144   buffer[1] = DOOF_CMD_SPI_WRITEREG;
1145   doof_blk = (DOOF_BLK *) (buffer + 2);
1146 
1147   doof_blk->addr = address;
1148   doof_blk->len = len;
1149 
1150   charptr = (unsigned char *) (buffer + sizeof (DOOF_BLK) + 2);
1151   memcpy ((void *) charptr, charbuf, len);
1152 
1153   if (!udp_ready_write (f))
1154     return FBLIB_EAGAIN;
1155 
1156   status = write (f->udp_socket, buffer, sizeof (DOOF_BLK) + 2 + len);
1157   if (status == -1)
1158     return FBLIB_EERRNO;
1159 
1160   /* read back */
1161   ret = poll_for_newpkt (f);
1162   if (ret != FBLIB_ESUCCESS)
1163     return ret;
1164 
1165   status = read (f->udp_socket, buffer, sizeof (buffer));
1166 
1167   if (status == -1)
1168     return FBLIB_EERRNO;
1169 
1170   if (buffer[1])
1171     {
1172       printf ("Error code reported from device: %d\n", buffer[1]);
1173       return -buffer[1];
1174     }
1175 
1176   if (status != (sizeof (DOOF_BLK) + 2))
1177     return FBLIB_EBYTECOUNT;
1178 
1179   return FBLIB_ESUCCESS;
1180 }
1181 
1182 /** @brief get the current link configuration over UDP
1183  *
1184  * @param f the device context
1185  * @param link_cfg A memory location that is at least  IDT_LINKS*sizeof(IDT_LINK_CONFIG) long
1186  * @return an fblib_err representing success or failure
1187  */
1188 fblib_err
configcheck_fb_udp(libfb_t * f,IDT_LINK_CONFIG * link_cfg)1189 configcheck_fb_udp (libfb_t * f, IDT_LINK_CONFIG * link_cfg)
1190 {
1191   int len = 2 + IDT_LINKS * sizeof (IDT_LINK_CONFIG);
1192   unsigned char buffer[len];
1193   ssize_t status;
1194   fblib_err ret;
1195 
1196   memset ((void *) buffer, 0, len);
1197   buffer[0] = 0x0;		/* Don't configure any spans */
1198   buffer[1] = DOOF_CMD_RECONFIG;
1199   status = write (f->udp_socket, buffer, len);
1200 
1201   if (status == -1)
1202     return FBLIB_EERRNO;
1203 
1204   /* read back */
1205   ret = poll_for_newpkt (f);
1206   if (ret != FBLIB_ESUCCESS)
1207     return ret;
1208 
1209   status = read (f->udp_socket, buffer, sizeof (buffer));
1210 
1211   if (status == -1)
1212     return FBLIB_EERRNO;
1213 
1214   if (buffer[1])
1215     {
1216       printf ("Error code reported from device: %d\n", buffer[1]);
1217       return -buffer[1];
1218     }
1219 
1220   if (status != len)
1221     return FBLIB_EBYTECOUNT;
1222 
1223   memcpy ((void *) link_cfg, &buffer[2],
1224 	  sizeof (IDT_LINK_CONFIG) * IDT_LINKS);
1225   return FBLIB_ESUCCESS;
1226 }
1227 
1228 /** @brief configure a device using span_mode masks with no LBO information
1229  * @deprecated span_mode masks are no longer used for configuration
1230  *
1231  * @param f the device context
1232  * @param span_mode configuration masks
1233  * @return an fblib_err representing success or failure
1234  */
1235 fblib_err
config_fb_udp(libfb_t * f,unsigned char * span_mode)1236 config_fb_udp (libfb_t * f, unsigned char *span_mode)
1237 {
1238   unsigned char zero[] = { 0, 0, 0, 0 };
1239   return config_fb_udp_lbo (f, span_mode, zero);
1240 }
1241 
1242 /** @brief configure a device using modern IDT_LINK_CONFIG data structures
1243  *
1244  * @param f the device context
1245  * @param configs an array of IDT_LINK_CONFIG structures, one for each span
1246  * @return an fblib_err representing success or failure
1247  */
1248 fblib_err
config_fb_udp_linkconfig(libfb_t * f,IDT_LINK_CONFIG * configs)1249 config_fb_udp_linkconfig (libfb_t * f, IDT_LINK_CONFIG * configs)
1250 {
1251   int len, span;
1252   unsigned char buffer[1500];
1253   ssize_t status;
1254   fblib_err ret;
1255   IDT_LINK_CONFIG *link_cfg;
1256 
1257   memset ((void *) buffer, 0, sizeof (buffer));
1258 
1259   /* Reconfigure all spans */
1260   buffer[0] = 0xF;
1261   buffer[1] = DOOF_CMD_RECONFIG;
1262   link_cfg = (IDT_LINK_CONFIG *) & (buffer[2]);
1263   for (span = 0; span < IDT_LINKS; span++)
1264     memcpy (&link_cfg[span], &configs[span], sizeof (IDT_LINK_CONFIG));
1265 
1266   len = 2 + IDT_LINKS * sizeof (IDT_LINK_CONFIG);
1267   if (!udp_ready_write (f))
1268     return FBLIB_EAGAIN;
1269 
1270   status = write (f->udp_socket, buffer, len);
1271   if (status == -1)
1272     return FBLIB_EERRNO;
1273 
1274   /* read back */
1275   ret = poll_for_newpkt (f);
1276   if (ret != FBLIB_ESUCCESS)
1277     return ret;
1278 
1279   status = read (f->udp_socket, buffer, sizeof (buffer));
1280 
1281   if (status == -1)
1282     return FBLIB_EERRNO;
1283 
1284   if (buffer[1])
1285     {
1286       printf ("Error code reported from device: %d\n", buffer[1]);
1287       return -buffer[1];
1288     }
1289 
1290   if (status != len)
1291     {
1292       printf ("Error in byte-count received\n");
1293       return -DOOF_RESP_BADSIZE;
1294     }
1295   return 0;
1296 }
1297 
1298 /** @brief configure a device using span_mode masks with LBO information
1299  * @deprecated span_mode masks are no longer used for configuration
1300  *
1301  * @param f the device context
1302  * @param span_mode configuration masks
1303  * @param puls an array of LBO, PULS_* settings, one for each span
1304  * @return an fblib_err representing success or failure
1305  */
1306 fblib_err
config_fb_udp_lbo(libfb_t * f,unsigned char * span_mode,unsigned char * puls)1307 config_fb_udp_lbo (libfb_t * f, unsigned char *span_mode, unsigned char *puls)
1308 {
1309   int len, span;
1310   unsigned char buffer[1500];
1311   IDT_LINK_CONFIG *link_cfg;
1312   ssize_t status;
1313   fblib_err ret;
1314 
1315   memset ((void *) buffer, 0, sizeof (buffer));
1316 
1317   /* Reconfig all spans */
1318   buffer[0] = 0xF;
1319   buffer[1] = DOOF_CMD_RECONFIG;
1320   link_cfg = (IDT_LINK_CONFIG *) & (buffer[2]);
1321 
1322   for (span = 0; span < IDT_LINKS; span++)
1323     {
1324       if (span_mode[span] & SPAN_MODE_E1)
1325 	link_cfg->E1Mode = 1;
1326       if (span_mode[span] & SPAN_MODE_ESF)
1327 	link_cfg->framing = 1;
1328       if (span_mode[span] & SPAN_MODE_AMI)
1329 	link_cfg->encoding = 1;
1330       if (span_mode[span] & SPAN_MODE_RBS)
1331 	link_cfg->rbs_en = 1;
1332       if (span_mode[span] & SPAN_MODE_CRCMF)
1333 	link_cfg->CRCMF = 1;
1334       if (span_mode[span] & SPAN_MODE_RLB)
1335 	link_cfg->rlb = 1;
1336       if (span_mode[span] & SPAN_MODE_EQ)
1337 	link_cfg->EQ = 1;
1338       if (span_mode[span] & SPAN_MODE_HDLC)
1339 	link_cfg->HDLC = 0x3;
1340 
1341       if (link_cfg->E1Mode == 0)
1342 	{
1343 	  /* PULS[3:0] only for T1/J1 */
1344 	  link_cfg->LBO = puls[span] & 0xF;
1345 	}
1346       else
1347 	{
1348 	  /* Just ensure PULS[3:0] is 0 for E1 */
1349 	  link_cfg->LBO = 0;
1350 	}
1351 
1352       link_cfg++;
1353     }
1354   len = 2 + IDT_LINKS * sizeof (IDT_LINK_CONFIG);
1355 
1356 #ifdef DEBUG
1357   fprintf (stderr, "LBO PULS: ");
1358   for (span = 0; span < IDT_LINKS; span++)
1359     {
1360       fprintf (stderr, "%02X ", puls[span] & 0xF);
1361     }
1362   fprintf (stderr, "\n");
1363   fprintf (stderr, "Uniform(?) span mode: 0x%02X\n", span_mode[0]);
1364 #endif
1365 
1366   if (!udp_ready_write (f))
1367     return FBLIB_EAGAIN;
1368 
1369   status = write (f->udp_socket, buffer, len);
1370   if (status == -1)
1371     return FBLIB_EERRNO;
1372 
1373   /* read back */
1374   ret = poll_for_newpkt (f);
1375   if (ret != FBLIB_ESUCCESS)
1376     return ret;
1377 #ifdef DEBUG
1378   fprintf (stderr, "Configured UDP socket %d\n", f->udp_socket);
1379 #endif
1380   status = read (f->udp_socket, buffer, sizeof (buffer));
1381 
1382   if (status == -1)
1383     return FBLIB_EERRNO;
1384 
1385   if (buffer[1])
1386     {
1387       printf ("Error code reported from device: %d\n", buffer[1]);
1388       return -buffer[1];
1389     }
1390 
1391   if (status != len)
1392     {
1393       printf ("Error in byte-count received\n");
1394       return -DOOF_RESP_BADSIZE;
1395     }
1396   return 0;
1397 }
1398 
1399 
1400 /** @brief check if CRC checking is enabled
1401  * @param f the device context
1402  * @return true if CRC checking is enabled
1403  */
1404 bool
libfb_getcrc(libfb_t * f)1405 libfb_getcrc (libfb_t * f)
1406 {
1407   if (f->crc_en == 1)
1408     return true;
1409   return false;
1410 }
1411 
1412 /** @brief set CRC checking value
1413  * @param f the device context
1414  * @param value 1 for enabling check, 0 to disable
1415  */
1416 static inline void
libfb_set_crc(libfb_t * f,int value)1417 libfb_set_crc (libfb_t * f, int value)
1418 {
1419   f->crc_en = value;
1420 }
1421 
1422 /** @brief toggle CRC checking on
1423  * @param f the device context
1424  */
1425 void
libfb_setcrc_on(libfb_t * f)1426 libfb_setcrc_on (libfb_t * f)
1427 {
1428   return libfb_set_crc (f, 1);
1429 }
1430 
1431 /** @brief toggle CRC checking off
1432  * @param f the device context
1433  */
1434 void
libfb_setcrc_off(libfb_t * f)1435 libfb_setcrc_off (libfb_t * f)
1436 {
1437   return libfb_set_crc (f, 0);
1438 }
1439 
1440 /** @brief Get the (local) source MAC address
1441  * @return pointer to the 6-byte MAC address
1442  */
1443 u_int8_t *
libfb_getsrcmac(libfb_t * f)1444 libfb_getsrcmac (libfb_t * f)
1445 {
1446   return f->s_mac;
1447 }
1448