1 /*
2  * Copyright (c) 2012 Adrien Guinet <adrien@guinet.me>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 	Redistributions of source code must retain the above copyright notice, this
9  * 	list of conditions and the following disclaimer.
10  *
11  * 	Redistributions in binary form must reproduce the above copyright notice,
12  * 	this list of conditions and the following disclaimer in the documentation
13  * 	and/or other materials provided with the distribution.
14  *
15  * 	Neither the name of Adrien Guinet nor the names of its
16  * 	contributors may be used to endorse or promote products derived from this
17  * 	software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <iostream>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <memory.h>
35 #include <pcap/pcap.h>
36 
37 #include <usbtop/buses.h>
38 
39 #include <tuple>
40 
41 #if defined(__FreeBSD__)
42 #define USB_DEVICE_START "usbus"
43 #else
44 #define USB_DEVICE_START "usbmon"
45 #endif
46 
47 static size_t g_len_usb_dev_start = strlen(USB_DEVICE_START);
48 
49 std::map<usbtop::UsbBus::id_type, usbtop::UsbBus> usbtop::UsbBuses::_buses;
50 bool usbtop::UsbBuses::_populated = false;
51 
list(bus_func_t f,const char * filter)52 void usbtop::UsbBuses::list(bus_func_t f, const char* filter)
53 {
54   char errbuf[PCAP_ERRBUF_SIZE];
55   pcap_if_t* list_devs;
56   if (pcap_findalldevs(&list_devs, errbuf) < 0) {
57     std::cerr << "Unable to list available devices: " << errbuf << std::endl;
58     pcap_freealldevs(list_devs);
59     exit(1);
60   }
61 
62   pcap_if_t* cur_dev = list_devs;
63   while (cur_dev) {
64     if (cur_dev->name) {
65       if ((strlen(cur_dev->name) > g_len_usb_dev_start) &&
66           (!filter || (filter && strcmp(cur_dev->name, filter) == 0)) &&
67           (memcmp(cur_dev->name, USB_DEVICE_START, g_len_usb_dev_start) == 0)) {
68         size_t bus_id = atoll(&cur_dev->name[g_len_usb_dev_start]);
69         f(bus_id, cur_dev->name, cur_dev->description);
70       }
71     }
72     cur_dev = cur_dev->next;
73   }
74 
75   pcap_freealldevs(list_devs);
76 }
77 
show(const char * filter)78 void usbtop::UsbBuses::show(const char* filter)
79 {
80   printf("Name\t\tDescription\n");
81   printf("---------------------------\n");
82 	list([](UsbBus::id_type /*bus_id*/, const char* name, const char* desc)
83     {
84       printf("%s", name);
85       if (desc) {
86         printf("\t\t%s", desc);
87       }
88       printf("\n");
89     }, filter);
90 }
91 
populate(const char * filter)92 void usbtop::UsbBuses::populate(const char* filter)
93 {
94   if (_populated) {
95     return;
96   }
97 
98   list([](UsbBus::id_type bus_id, const char* name, const char* desc)
99     {
100       add_bus(bus_id, name, desc);
101     }, filter);
102   _populated = true;
103 }
104 
add_bus(UsbBus::id_type bus_id,const char * name,const char * desc)105 void usbtop::UsbBuses::add_bus(UsbBus::id_type bus_id, const char* name, const char* desc)
106 {
107   _buses.emplace(std::piecewise_construct,
108       std::forward_as_tuple(bus_id),
109       std::forward_as_tuple(bus_id, name, desc));
110 }
111 
get_bus(UsbBus::id_type bus_id)112 usbtop::UsbBus* usbtop::UsbBuses::get_bus(UsbBus::id_type bus_id)
113 {
114   list_buses_t::iterator it = _buses.find(bus_id);
115   if (it == _buses.end()) {
116     return NULL;
117   }
118 
119   return &it->second;
120 }
121 
size()122 size_t usbtop::UsbBuses::size()
123 {
124   return _buses.size();
125 }
126