Update rawsock code
[oweals/nmrpflash.git] / rawsock.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <pcap.h>
5
6 struct rawsock
7 {
8         pcap_t *pcap;
9         struct timeval timeout;
10         int fd;
11 };
12
13 struct rawsock *rawsock_create(const char *interface)
14 {
15         char errbuf[PCAP_ERRBUF_SIZE];
16         struct bpf_program fp;
17         struct rawsock *sock;
18         int err;
19
20         sock = malloc(sizeof(struct rawsock));
21         if (!sock) {
22                 perror("malloc");
23                 return NULL;
24         }
25
26         errbuf[0] = '\0';
27
28         sock->pcap = pcap_open_live(interface, BUFSIZ, 1, 1, errbuf);
29         if (!sock->pcap) {
30                 fprintf(stderr, "pcap_open_live: %s\n", errbuf);
31                 goto cleanup_malloc;
32         }
33
34         if (*errbuf) {
35                 fprintf(stderr, "Warning: %s.\n", errbuf);
36         }
37
38         if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
39                 fprintf(stderr, "Interface %s not supported.\n", interface);
40                 goto cleanup_pcap;
41         }
42
43         err = pcap_compile(sock->pcap, &fp, "ether proto 0x0912", 0,
44                         PCAP_NETMASK_UNKNOWN);
45         if (err) {
46                 pcap_perror(sock->pcap, "pcap_compile");
47                 goto cleanup_pcap;
48         }
49
50         if ((err = pcap_setfilter(sock->pcap, &fp))) {
51                 pcap_perror(sock->pcap, "pcap_setfilter");
52                 goto cleanup_pcap;
53         }
54
55         sock->fd = pcap_get_selectable_fd(sock->pcap);
56         if (sock->fd == -1) {
57                 fprintf(stderr, "No selectable file descriptor available.\n");
58                 goto cleanup_pcap;
59         }
60
61         return sock;
62
63 cleanup_pcap:
64         pcap_close(sock->pcap);
65 cleanup_malloc:
66         free(sock);
67         return NULL;
68 }
69
70 int rawsock_recv(struct rawsock *sock, uint8_t **buffer, unsigned *size)
71 {
72         struct pcap_pkthdr* hdr;
73         int status;
74         fd_set fds;
75
76         if (sock->timeout.tv_sec || sock->timeout.tv_usec) {
77                 FD_ZERO(&fds);
78                 FD_SET(sock->fd, &fds);
79
80                 status = select(sock->fd + 1, &fds, NULL, NULL, &sock->timeout);
81                 if (status == -1) {
82                         perror("select");
83                         return -1;
84                 } else if (status == 0) {
85                         return 1;
86                 }
87         }
88
89         status = pcap_next_ex(sock->pcap, &hdr, (const u_char**)buffer);
90         switch (status) {
91                 case 1:
92                         status = 0;
93                         *size = hdr->caplen;
94                         break;
95                 case 0:
96                         status = 1;
97                         break;
98                 case -1:
99                         pcap_perror(sock->pcap, "pcap_next_ex");
100                         status = -1;
101                         break;
102                 default:
103                         fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
104                         status = -1;
105                         break;
106         }
107
108         return status;
109 }
110
111 int rawsock_send(struct rawsock *sock, uint8_t *buffer, size_t size)
112 {
113 #if defined(_WIN32) || defined(_WIN64)
114         if (pcap_sendpacket(sock->pcap, buffer, size) == 0) {
115                 return 0;
116         } else {
117                 pcap_perror(sock->pcap, "pcap_sendpacket");
118                 return -1;
119         }
120 #else
121         if (pcap_inject(sock->pcap, buffer, size) != size) {
122                 return 0;
123         } else {
124                 pcap_perror(sock->pcap, "pcap_inject");
125                 return -1;
126         }
127 #endif
128 }
129
130 int rawsock_close(struct rawsock *sock)
131 {
132         pcap_close(sock->pcap);
133         free(sock);
134         return 0;
135 }
136
137 int rawsock_set_timeout(struct rawsock *sock, unsigned msec)
138 {
139         sock->timeout.tv_sec = msec / 1000;
140         sock->timeout.tv_usec = (msec % 1000) * 1000;
141         return 0;
142 }