| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* You may distribute under the terms of either the GNU General Public License |
|
2
|
|
|
|
|
|
|
* or the Artistic License (the same terms as Perl itself) |
|
3
|
|
|
|
|
|
|
* |
|
4
|
|
|
|
|
|
|
* (C) Paul Evans, 2009,2010 -- leonerd@leonerd.org.uk |
|
5
|
|
|
|
|
|
|
*/ |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
8
|
|
|
|
|
|
|
#include "perl.h" |
|
9
|
|
|
|
|
|
|
#include "XSUB.h" |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
#include |
|
12
|
|
|
|
|
|
|
#include |
|
13
|
|
|
|
|
|
|
#include |
|
14
|
|
|
|
|
|
|
#include |
|
15
|
|
|
|
|
|
|
#include |
|
16
|
|
|
|
|
|
|
#include |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
/* Borrowed from IO/Sockatmark.xs */ |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
#ifdef PerlIO |
|
21
|
|
|
|
|
|
|
typedef PerlIO * InputStream; |
|
22
|
|
|
|
|
|
|
#else |
|
23
|
|
|
|
|
|
|
#define PERLIO_IS_STDIO 1 |
|
24
|
|
|
|
|
|
|
typedef FILE * InputStream; |
|
25
|
|
|
|
|
|
|
#define PerlIO_fileno(f) fileno(f) |
|
26
|
|
|
|
|
|
|
#endif |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
/* Lower and upper bounds of a valid struct sockaddr_ll */ |
|
29
|
|
|
|
|
|
|
static int sll_max; |
|
30
|
|
|
|
|
|
|
static int sll_min; |
|
31
|
|
|
|
|
|
|
/* Maximum number of address bytes in a struct sockaddr_ll */ |
|
32
|
|
|
|
|
|
|
static int sll_maxaddr; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
#ifndef PUSHmortal |
|
35
|
|
|
|
|
|
|
# define PUSHmortal PUSHs(sv_newmortal()) |
|
36
|
|
|
|
|
|
|
#endif |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
#ifndef mPUSHi |
|
39
|
|
|
|
|
|
|
# define mPUSHi(iv) sv_setiv(PUSHmortal, iv) |
|
40
|
|
|
|
|
|
|
#endif |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
#ifndef mPUSHn |
|
43
|
|
|
|
|
|
|
# define mPUSHn(nv) sv_setnv(PUSHmortal, nv) |
|
44
|
|
|
|
|
|
|
#endif |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
#ifndef mPUSHp |
|
47
|
|
|
|
|
|
|
# define mPUSHp(p,l) sv_setpvn(PUSHmortal, p, l) |
|
48
|
|
|
|
|
|
|
#endif |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
#define HVSTOREi(hv,name,iv) sv_setiv(*hv_fetch(hv, ""name"", sizeof(""name"")-1, 1), iv) |
|
51
|
|
|
|
|
|
|
#define HVSTOREp(hv,name,pv,len) sv_setpvn(*hv_fetch(hv, ""name"", sizeof(""name"")-1, 1), pv, len) |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
#if defined(HAVE_TPACKET) || defined(HAVE_TPACKET2) |
|
54
|
|
|
|
|
|
|
# define HAVE_RX_RING |
|
55
|
|
|
|
|
|
|
static int free_rxring_state(pTHX_ SV *, MAGIC *); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
static MGVTBL vtbl = { |
|
58
|
|
|
|
|
|
|
NULL, /* get */ |
|
59
|
|
|
|
|
|
|
NULL, /* set */ |
|
60
|
|
|
|
|
|
|
NULL, /* len */ |
|
61
|
|
|
|
|
|
|
NULL, /* clear */ |
|
62
|
|
|
|
|
|
|
&free_rxring_state, /* free */ |
|
63
|
|
|
|
|
|
|
}; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
struct packet_rxring_state |
|
66
|
|
|
|
|
|
|
{ |
|
67
|
|
|
|
|
|
|
char *buffer; |
|
68
|
|
|
|
|
|
|
unsigned int frame_size; |
|
69
|
|
|
|
|
|
|
unsigned int frame_nr; |
|
70
|
|
|
|
|
|
|
unsigned int frame_idx; |
|
71
|
|
|
|
|
|
|
}; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
static int free_rxring_state(pTHX_ SV *sv, MAGIC *mg) |
|
74
|
|
|
|
|
|
|
{ |
|
75
|
|
|
|
|
|
|
free(mg->mg_ptr); |
|
76
|
|
|
|
|
|
|
return 0; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
static struct packet_rxring_state *get_rxring_state(SV *sv) |
|
80
|
|
|
|
|
|
|
{ |
|
81
|
|
|
|
|
|
|
MAGIC *magic; |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
for(magic = mg_find(sv, PERL_MAGIC_ext); magic; magic = magic->mg_moremagic) { |
|
84
|
|
|
|
|
|
|
if(magic->mg_type == PERL_MAGIC_ext && magic->mg_virtual == &vtbl) { |
|
85
|
|
|
|
|
|
|
return (struct packet_rxring_state *)magic->mg_ptr; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
croak("Cannot find rxring state - call setup_rx_ring() first"); |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
static void *frame_ptr(struct packet_rxring_state *state) |
|
93
|
|
|
|
|
|
|
{ |
|
94
|
|
|
|
|
|
|
return state->buffer + (state->frame_size * state->frame_idx); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
#endif |
|
97
|
|
|
|
|
|
|
|
|
98
|
8
|
|
|
|
|
|
static void setup_constants(void) |
|
99
|
|
|
|
|
|
|
{ |
|
100
|
8
|
|
|
|
|
|
sll_max = sizeof(struct sockaddr_ll); |
|
101
|
8
|
|
|
|
|
|
sll_maxaddr = sizeof(((struct sockaddr_ll*)NULL)->sll_addr); |
|
102
|
8
|
|
|
|
|
|
sll_min = sll_max - sll_maxaddr; |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
HV *stash; |
|
105
|
|
|
|
|
|
|
AV *export; |
|
106
|
|
|
|
|
|
|
|
|
107
|
8
|
|
|
|
|
|
stash = gv_stashpvn("Socket::Packet", 14, TRUE); |
|
108
|
8
|
|
|
|
|
|
export = get_av("Socket::Packet::EXPORT", TRUE); |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
#define DO_CONSTANT(c) \ |
|
111
|
|
|
|
|
|
|
newCONSTSUB(stash, #c, newSViv(c)); \ |
|
112
|
|
|
|
|
|
|
av_push(export, newSVpv(#c, 0)); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
|
115
|
8
|
|
|
|
|
|
DO_CONSTANT(PF_PACKET) |
|
116
|
8
|
|
|
|
|
|
DO_CONSTANT(AF_PACKET) |
|
117
|
|
|
|
|
|
|
|
|
118
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_HOST) |
|
119
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_BROADCAST) |
|
120
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_MULTICAST) |
|
121
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_OTHERHOST) |
|
122
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_OUTGOING) |
|
123
|
|
|
|
|
|
|
|
|
124
|
8
|
|
|
|
|
|
DO_CONSTANT(ETH_P_ALL) |
|
125
|
|
|
|
|
|
|
|
|
126
|
8
|
|
|
|
|
|
DO_CONSTANT(SOL_PACKET) |
|
127
|
|
|
|
|
|
|
|
|
128
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_ADD_MEMBERSHIP) |
|
129
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_DROP_MEMBERSHIP) |
|
130
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_STATISTICS) |
|
131
|
|
|
|
|
|
|
#ifdef HAVE_ORIGDEV |
|
132
|
|
|
|
|
|
|
DO_CONSTANT(PACKET_ORIGDEV) |
|
133
|
|
|
|
|
|
|
#endif |
|
134
|
|
|
|
|
|
|
|
|
135
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_MR_MULTICAST) |
|
136
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_MR_PROMISC) |
|
137
|
8
|
|
|
|
|
|
DO_CONSTANT(PACKET_MR_ALLMULTI) |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
#ifdef HAVE_RX_RING |
|
140
|
|
|
|
|
|
|
DO_CONSTANT(TP_STATUS_KERNEL) |
|
141
|
|
|
|
|
|
|
DO_CONSTANT(TP_STATUS_USER) |
|
142
|
|
|
|
|
|
|
DO_CONSTANT(TP_STATUS_COPY) |
|
143
|
|
|
|
|
|
|
DO_CONSTANT(TP_STATUS_LOSING) |
|
144
|
|
|
|
|
|
|
DO_CONSTANT(TP_STATUS_CSUMNOTREADY) |
|
145
|
|
|
|
|
|
|
#endif |
|
146
|
8
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
MODULE = Socket::Packet PACKAGE = Socket::Packet |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
BOOT: |
|
151
|
8
|
|
|
|
|
|
setup_constants(); |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
void |
|
154
|
|
|
|
|
|
|
pack_sockaddr_ll(protocol, ifindex, hatype, pkttype, addr) |
|
155
|
|
|
|
|
|
|
unsigned short protocol |
|
156
|
|
|
|
|
|
|
int ifindex |
|
157
|
|
|
|
|
|
|
unsigned short hatype |
|
158
|
|
|
|
|
|
|
unsigned char pkttype |
|
159
|
|
|
|
|
|
|
SV *addr |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
PREINIT: |
|
162
|
|
|
|
|
|
|
struct sockaddr_ll sll; |
|
163
|
|
|
|
|
|
|
char *addrbytes; |
|
164
|
|
|
|
|
|
|
STRLEN addrlen; |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
PPCODE: |
|
167
|
4
|
50
|
|
|
|
|
if (DO_UTF8(addr) && !sv_utf8_downgrade(addr, 1)) |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
|
croak("Wide character in Socket::Packet::pack_sockaddr_ll"); |
|
169
|
|
|
|
|
|
|
|
|
170
|
4
|
50
|
|
|
|
|
addrbytes = SvPVbyte(addr, addrlen); |
|
171
|
|
|
|
|
|
|
|
|
172
|
4
|
50
|
|
|
|
|
if(addrlen > sll_maxaddr) |
|
173
|
0
|
|
|
|
|
|
croak("addr too long; should be no more than %d bytes, found %d", sll_maxaddr, addrlen); |
|
174
|
|
|
|
|
|
|
|
|
175
|
4
|
|
|
|
|
|
sll.sll_family = AF_PACKET; |
|
176
|
4
|
50
|
|
|
|
|
sll.sll_protocol = htons(protocol); |
|
177
|
4
|
|
|
|
|
|
sll.sll_ifindex = ifindex; |
|
178
|
4
|
|
|
|
|
|
sll.sll_hatype = hatype; |
|
179
|
4
|
|
|
|
|
|
sll.sll_pkttype = pkttype; |
|
180
|
|
|
|
|
|
|
|
|
181
|
4
|
|
|
|
|
|
sll.sll_halen = addrlen; |
|
182
|
|
|
|
|
|
|
Zero(&sll.sll_addr, sll_maxaddr, char); |
|
183
|
|
|
|
|
|
|
Copy(addrbytes, &sll.sll_addr, addrlen, char); |
|
184
|
|
|
|
|
|
|
|
|
185
|
4
|
50
|
|
|
|
|
EXTEND(SP, 1); |
|
186
|
4
|
|
|
|
|
|
mPUSHp((char *)&sll, sizeof sll); |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
void |
|
189
|
|
|
|
|
|
|
unpack_sockaddr_ll(sa) |
|
190
|
|
|
|
|
|
|
SV * sa |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
PREINIT: |
|
193
|
|
|
|
|
|
|
STRLEN sa_len; |
|
194
|
|
|
|
|
|
|
char *sa_bytes; |
|
195
|
|
|
|
|
|
|
struct sockaddr_ll sll; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
PPCODE: |
|
198
|
|
|
|
|
|
|
/* variable size of structure, because of variable length of addr bytes */ |
|
199
|
10
|
50
|
|
|
|
|
sa_bytes = SvPVbyte(sa, sa_len); |
|
200
|
10
|
50
|
|
|
|
|
if(sa_len < sll_min) |
|
201
|
0
|
|
|
|
|
|
croak("Socket address too small; found %d bytes, expected at least %d", sa_len, sll_min); |
|
202
|
10
|
50
|
|
|
|
|
if(sa_len > sll_max) |
|
203
|
0
|
|
|
|
|
|
croak("Socket address too big; found %d bytes, expected at most %d", sa_len, sll_max); |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
Copy(sa_bytes, &sll, sizeof sll, char); |
|
206
|
|
|
|
|
|
|
|
|
207
|
10
|
50
|
|
|
|
|
if(sa_len < sll_min + sll.sll_halen) |
|
208
|
0
|
|
|
|
|
|
croak("Socket address too small; it did not provide enough bytes for sll_halen of %d", sll.sll_halen); |
|
209
|
|
|
|
|
|
|
|
|
210
|
10
|
50
|
|
|
|
|
if(sll.sll_family != AF_PACKET) |
|
211
|
0
|
|
|
|
|
|
croak("Bad address family for unpack_sockaddr_ll: got %d, expected %d", sll.sll_family, AF_PACKET); |
|
212
|
|
|
|
|
|
|
|
|
213
|
10
|
50
|
|
|
|
|
EXTEND(SP, 5); |
|
214
|
10
|
50
|
|
|
|
|
mPUSHi(ntohs(sll.sll_protocol)); |
|
215
|
10
|
|
|
|
|
|
mPUSHi(sll.sll_ifindex); |
|
216
|
10
|
|
|
|
|
|
mPUSHi(sll.sll_hatype); |
|
217
|
10
|
|
|
|
|
|
mPUSHi(sll.sll_pkttype); |
|
218
|
10
|
|
|
|
|
|
mPUSHp((char *)sll.sll_addr, sll.sll_halen); |
|
219
|
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
void |
|
221
|
|
|
|
|
|
|
pack_packet_mreq(ifindex, type, addr) |
|
222
|
|
|
|
|
|
|
int ifindex |
|
223
|
|
|
|
|
|
|
unsigned short type |
|
224
|
|
|
|
|
|
|
SV * addr |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
PREINIT: |
|
227
|
|
|
|
|
|
|
struct packet_mreq mreq; |
|
228
|
|
|
|
|
|
|
char *addr_bytes; |
|
229
|
|
|
|
|
|
|
STRLEN addr_len; |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
PPCODE: |
|
232
|
0
|
0
|
|
|
|
|
if (DO_UTF8(addr) && !sv_utf8_downgrade(addr, 1)) |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
croak("Wide character in Socket::Packet::pack_sockaddr_ll"); |
|
234
|
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
|
addr_bytes = SvPVbyte(addr, addr_len); |
|
236
|
|
|
|
|
|
|
|
|
237
|
0
|
0
|
|
|
|
|
if(addr_len > sizeof(mreq.mr_address)) |
|
238
|
0
|
|
|
|
|
|
croak("addr too long; should be no more than %d bytes, found %d", sizeof(mreq.mr_address), addr_len); |
|
239
|
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
|
mreq.mr_ifindex = ifindex; |
|
241
|
0
|
|
|
|
|
|
mreq.mr_type = type; |
|
242
|
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
mreq.mr_alen = addr_len; |
|
244
|
|
|
|
|
|
|
Zero(&mreq.mr_address, sizeof(mreq.mr_address), char); |
|
245
|
|
|
|
|
|
|
Copy(addr_bytes, &mreq.mr_address, addr_len, char); |
|
246
|
|
|
|
|
|
|
|
|
247
|
0
|
0
|
|
|
|
|
EXTEND(SP, 1); |
|
248
|
0
|
|
|
|
|
|
mPUSHp((char *)&mreq, sizeof mreq); |
|
249
|
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
void |
|
251
|
|
|
|
|
|
|
unpack_packet_mreq(data) |
|
252
|
|
|
|
|
|
|
SV * data |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
PREINIT: |
|
255
|
|
|
|
|
|
|
STRLEN data_len; |
|
256
|
|
|
|
|
|
|
char *data_bytes; |
|
257
|
|
|
|
|
|
|
struct packet_mreq mreq; |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
PPCODE: |
|
260
|
0
|
0
|
|
|
|
|
data_bytes = SvPVbyte(data, data_len); |
|
261
|
0
|
0
|
|
|
|
|
if(data_len != sizeof(mreq)) |
|
262
|
0
|
|
|
|
|
|
croak("packet_mreq buffer incorrect size; found %d bytes, expected %d", data_len, sizeof(mreq)); |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Copy(data_bytes, &mreq, data_len, char); |
|
265
|
|
|
|
|
|
|
|
|
266
|
0
|
0
|
|
|
|
|
if(mreq.mr_alen > sizeof(mreq.mr_address)) |
|
267
|
0
|
|
|
|
|
|
croak("packet_mreq claims to have a larger address than it has space for"); |
|
268
|
|
|
|
|
|
|
|
|
269
|
0
|
0
|
|
|
|
|
EXTEND(SP, 3); |
|
270
|
0
|
|
|
|
|
|
mPUSHi(mreq.mr_ifindex); |
|
271
|
0
|
|
|
|
|
|
mPUSHi(mreq.mr_type); |
|
272
|
0
|
|
|
|
|
|
mPUSHp(mreq.mr_address, mreq.mr_alen); |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
void |
|
275
|
|
|
|
|
|
|
unpack_tpacket_stats(stats) |
|
276
|
|
|
|
|
|
|
SV * stats |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
PREINIT: |
|
279
|
|
|
|
|
|
|
STRLEN stats_len; |
|
280
|
|
|
|
|
|
|
char *stats_bytes; |
|
281
|
|
|
|
|
|
|
struct tpacket_stats statsbuf; |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
PPCODE: |
|
284
|
1
|
50
|
|
|
|
|
stats_bytes = SvPVbyte(stats, stats_len); |
|
285
|
1
|
50
|
|
|
|
|
if(stats_len != sizeof(statsbuf)) |
|
286
|
0
|
|
|
|
|
|
croak("tpacket_stats buffer incorrect size; found %d bytes, expected %d", stats_len, sizeof(statsbuf)); |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
Copy(stats_bytes, &statsbuf, stats_len, char); |
|
289
|
|
|
|
|
|
|
|
|
290
|
1
|
50
|
|
|
|
|
EXTEND(SP, 5); |
|
291
|
1
|
|
|
|
|
|
mPUSHi(statsbuf.tp_packets); |
|
292
|
1
|
|
|
|
|
|
mPUSHi(statsbuf.tp_drops); |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
void |
|
295
|
|
|
|
|
|
|
siocgstamp(sock) |
|
296
|
|
|
|
|
|
|
InputStream sock |
|
297
|
|
|
|
|
|
|
PROTOTYPE: $ |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
PREINIT: |
|
300
|
|
|
|
|
|
|
int fd; |
|
301
|
|
|
|
|
|
|
int result; |
|
302
|
|
|
|
|
|
|
struct timeval tv; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
PPCODE: |
|
305
|
3
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
306
|
3
|
50
|
|
|
|
|
if(ioctl(fd, SIOCGSTAMP, &tv) == -1) { |
|
307
|
3
|
100
|
|
|
|
|
if(GIMME_V == G_ARRAY) |
|
|
|
50
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
return; |
|
309
|
|
|
|
|
|
|
else |
|
310
|
3
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
|
|
313
|
0
|
0
|
|
|
|
|
if(GIMME_V == G_ARRAY) { |
|
|
|
0
|
|
|
|
|
|
|
314
|
0
|
0
|
|
|
|
|
EXTEND(SP, 2); |
|
315
|
0
|
|
|
|
|
|
mPUSHi(tv.tv_sec); |
|
316
|
0
|
|
|
|
|
|
mPUSHi(tv.tv_usec); |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
else { |
|
319
|
0
|
|
|
|
|
|
mPUSHn((double)tv.tv_sec + (tv.tv_usec / 1000000.0)); |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
void |
|
323
|
|
|
|
|
|
|
siocgstampns(sock) |
|
324
|
|
|
|
|
|
|
InputStream sock |
|
325
|
|
|
|
|
|
|
PROTOTYPE: $ |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
PREINIT: |
|
328
|
|
|
|
|
|
|
int fd; |
|
329
|
|
|
|
|
|
|
int result; |
|
330
|
|
|
|
|
|
|
struct timespec ts; |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
PPCODE: |
|
333
|
|
|
|
|
|
|
#ifdef SIOCGSTAMPNS |
|
334
|
0
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
335
|
0
|
0
|
|
|
|
|
if(ioctl(fd, SIOCGSTAMPNS, &ts) == -1) { |
|
336
|
0
|
0
|
|
|
|
|
if(GIMME_V == G_ARRAY) |
|
|
|
0
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
return; |
|
338
|
|
|
|
|
|
|
else |
|
339
|
0
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
0
|
0
|
|
|
|
|
if(GIMME_V == G_ARRAY) { |
|
|
|
0
|
|
|
|
|
|
|
343
|
0
|
0
|
|
|
|
|
EXTEND(SP, 2); |
|
344
|
0
|
|
|
|
|
|
mPUSHi(ts.tv_sec); |
|
345
|
0
|
|
|
|
|
|
mPUSHi(ts.tv_nsec); |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
else { |
|
348
|
0
|
|
|
|
|
|
mPUSHn((double)ts.tv_sec + (ts.tv_nsec / 1000000000.0)); |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
#else |
|
351
|
|
|
|
|
|
|
croak("SIOCGSTAMPNS not implemented"); |
|
352
|
|
|
|
|
|
|
#endif |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
void |
|
355
|
|
|
|
|
|
|
siocgifindex(sock, ifname) |
|
356
|
|
|
|
|
|
|
InputStream sock |
|
357
|
|
|
|
|
|
|
char *ifname |
|
358
|
|
|
|
|
|
|
PROTOTYPE: $$ |
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
PREINIT: |
|
361
|
|
|
|
|
|
|
int fd; |
|
362
|
|
|
|
|
|
|
struct ifreq req; |
|
363
|
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
PPCODE: |
|
365
|
|
|
|
|
|
|
#ifdef SIOCGIFINDEX |
|
366
|
3
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
367
|
|
|
|
|
|
|
strncpy(req.ifr_name, ifname, IFNAMSIZ); |
|
368
|
3
|
50
|
|
|
|
|
if(ioctl(fd, SIOCGIFINDEX, &req) == -1) |
|
369
|
0
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
370
|
3
|
|
|
|
|
|
mPUSHi(req.ifr_ifindex); |
|
371
|
|
|
|
|
|
|
#else |
|
372
|
|
|
|
|
|
|
croak("SIOCGIFINDEX not implemented"); |
|
373
|
|
|
|
|
|
|
#endif |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
void |
|
376
|
|
|
|
|
|
|
siocgifname(sock, ifindex) |
|
377
|
|
|
|
|
|
|
InputStream sock |
|
378
|
|
|
|
|
|
|
int ifindex |
|
379
|
|
|
|
|
|
|
PROTOTYPE: $$ |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
PREINIT: |
|
382
|
|
|
|
|
|
|
int fd; |
|
383
|
|
|
|
|
|
|
struct ifreq req; |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
PPCODE: |
|
386
|
|
|
|
|
|
|
#ifdef SIOCGIFNAME |
|
387
|
7
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
388
|
7
|
|
|
|
|
|
req.ifr_ifindex = ifindex; |
|
389
|
7
|
100
|
|
|
|
|
if(ioctl(fd, SIOCGIFNAME, &req) == -1) |
|
390
|
2
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
391
|
5
|
|
|
|
|
|
PUSHs(sv_2mortal(newSVpv(req.ifr_name, 0))); |
|
392
|
|
|
|
|
|
|
#else |
|
393
|
|
|
|
|
|
|
croak("SIOCGIFNAME not implemented"); |
|
394
|
|
|
|
|
|
|
#endif |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
void |
|
397
|
|
|
|
|
|
|
recv_len(sock, buffer, maxlen, flags) |
|
398
|
|
|
|
|
|
|
InputStream sock |
|
399
|
|
|
|
|
|
|
SV *buffer |
|
400
|
|
|
|
|
|
|
int maxlen |
|
401
|
|
|
|
|
|
|
int flags |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
PREINIT: |
|
404
|
|
|
|
|
|
|
int fd; |
|
405
|
|
|
|
|
|
|
char *bufferp; |
|
406
|
|
|
|
|
|
|
struct sockaddr_storage addr; |
|
407
|
|
|
|
|
|
|
socklen_t addrlen; |
|
408
|
|
|
|
|
|
|
int len; |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
PPCODE: |
|
411
|
1
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
412
|
|
|
|
|
|
|
|
|
413
|
1
|
50
|
|
|
|
|
if(!SvOK(buffer)) |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
414
|
1
|
|
|
|
|
|
sv_setpvn(buffer, "", 0); |
|
415
|
|
|
|
|
|
|
|
|
416
|
1
|
50
|
|
|
|
|
bufferp = SvGROW(buffer, (STRLEN)(maxlen+1)); |
|
|
|
50
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
|
|
418
|
1
|
|
|
|
|
|
addrlen = sizeof(addr); |
|
419
|
|
|
|
|
|
|
|
|
420
|
2
|
|
|
|
|
|
len = recvfrom(fd, bufferp, maxlen, flags, (struct sockaddr *)&addr, &addrlen); |
|
421
|
|
|
|
|
|
|
|
|
422
|
1
|
50
|
|
|
|
|
if(len < 0) |
|
423
|
0
|
|
|
|
|
|
XSRETURN(0); |
|
424
|
|
|
|
|
|
|
|
|
425
|
1
|
50
|
|
|
|
|
if(len > maxlen) |
|
426
|
1
|
|
|
|
|
|
SvCUR_set(buffer, maxlen); |
|
427
|
|
|
|
|
|
|
else |
|
428
|
0
|
|
|
|
|
|
SvCUR_set(buffer, len); |
|
429
|
|
|
|
|
|
|
|
|
430
|
1
|
|
|
|
|
|
*SvEND(buffer) = '\0'; |
|
431
|
1
|
|
|
|
|
|
SvPOK_only(buffer); |
|
432
|
|
|
|
|
|
|
|
|
433
|
1
|
|
|
|
|
|
mPUSHp((char *)&addr, addrlen); |
|
434
|
1
|
|
|
|
|
|
mPUSHi(len); |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
void |
|
437
|
|
|
|
|
|
|
setup_rx_ring(sock, frame_size, frame_nr, block_size) |
|
438
|
|
|
|
|
|
|
InputStream sock |
|
439
|
|
|
|
|
|
|
unsigned int frame_size |
|
440
|
|
|
|
|
|
|
unsigned int frame_nr |
|
441
|
|
|
|
|
|
|
unsigned int block_size |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
PREINIT: |
|
444
|
|
|
|
|
|
|
int fd; |
|
445
|
|
|
|
|
|
|
int version; |
|
446
|
|
|
|
|
|
|
struct tpacket_req req; |
|
447
|
|
|
|
|
|
|
size_t size; |
|
448
|
|
|
|
|
|
|
char *addr; |
|
449
|
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
PPCODE: |
|
451
|
|
|
|
|
|
|
#ifdef HAVE_RX_RING |
|
452
|
|
|
|
|
|
|
fd = PerlIO_fileno(sock); |
|
453
|
|
|
|
|
|
|
#ifdef HAVE_TPACKET2 |
|
454
|
|
|
|
|
|
|
version = TPACKET_V2; |
|
455
|
|
|
|
|
|
|
if(setsockopt(fd, SOL_PACKET, PACKET_VERSION, &version, sizeof version) != 0) |
|
456
|
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
457
|
|
|
|
|
|
|
#endif |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
{ |
|
460
|
|
|
|
|
|
|
struct tpacket_req req; |
|
461
|
|
|
|
|
|
|
req.tp_frame_size = frame_size; |
|
462
|
|
|
|
|
|
|
req.tp_frame_nr = frame_nr; |
|
463
|
|
|
|
|
|
|
req.tp_block_size = block_size; |
|
464
|
|
|
|
|
|
|
req.tp_block_nr = (frame_size * frame_nr) / block_size; |
|
465
|
|
|
|
|
|
|
if(setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &req, sizeof req) != 0) |
|
466
|
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
size = req.tp_block_size * req.tp_block_nr; |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
addr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); |
|
472
|
|
|
|
|
|
|
if(addr == MAP_FAILED) |
|
473
|
|
|
|
|
|
|
XSRETURN_UNDEF; |
|
474
|
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
{ |
|
476
|
|
|
|
|
|
|
struct packet_rxring_state *state = malloc(sizeof *state); |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
state->buffer = addr; |
|
479
|
|
|
|
|
|
|
state->frame_size = frame_size; |
|
480
|
|
|
|
|
|
|
state->frame_nr = frame_nr; |
|
481
|
|
|
|
|
|
|
state->frame_idx = 0; |
|
482
|
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sv_magicext((SV*)sv_2io(ST(0)), NULL, PERL_MAGIC_ext, &vtbl, (char *)state, 0); |
|
484
|
|
|
|
|
|
|
} |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
ST(0) = sv_2mortal(newSViv(size)); |
|
487
|
|
|
|
|
|
|
XSRETURN(1); |
|
488
|
|
|
|
|
|
|
#else |
|
489
|
0
|
|
|
|
|
|
croak("setup_rx_ring() not supported on this platform"); |
|
490
|
|
|
|
|
|
|
#endif |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
void |
|
493
|
|
|
|
|
|
|
get_ring_frame_status(sock) |
|
494
|
|
|
|
|
|
|
InputStream sock |
|
495
|
|
|
|
|
|
|
PPCODE: |
|
496
|
|
|
|
|
|
|
#ifdef HAVE_RX_RING |
|
497
|
|
|
|
|
|
|
{ |
|
498
|
|
|
|
|
|
|
struct packet_rxring_state *state = get_rxring_state((SV*)sv_2io(ST(0))); |
|
499
|
|
|
|
|
|
|
char *addr = frame_ptr(state); |
|
500
|
|
|
|
|
|
|
#if defined(HAVE_TPACKET2) |
|
501
|
|
|
|
|
|
|
struct tpacket2_hdr *hdr = (struct tpacket2_hdr *)addr; |
|
502
|
|
|
|
|
|
|
#elif defined(HAVE_TPACKET) |
|
503
|
|
|
|
|
|
|
struct tpacket_hdr *hdr = (struct tpacket_hdr *)addr; |
|
504
|
|
|
|
|
|
|
#endif |
|
505
|
|
|
|
|
|
|
ST(0) = sv_2mortal(newSViv(hdr->tp_status)); |
|
506
|
|
|
|
|
|
|
} |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
XSRETURN(1); |
|
509
|
|
|
|
|
|
|
#else |
|
510
|
0
|
|
|
|
|
|
croak("get_ring_frame_status() not supported on this platform"); |
|
511
|
|
|
|
|
|
|
#endif |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
void |
|
514
|
|
|
|
|
|
|
get_ring_frame(sock, buffer, info) |
|
515
|
|
|
|
|
|
|
InputStream sock |
|
516
|
|
|
|
|
|
|
SV *buffer |
|
517
|
|
|
|
|
|
|
HV *info |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
PREINIT: |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
PPCODE: |
|
522
|
|
|
|
|
|
|
#ifdef HAVE_RX_RING |
|
523
|
|
|
|
|
|
|
{ |
|
524
|
|
|
|
|
|
|
struct packet_rxring_state *state = get_rxring_state((SV*)sv_2io(ST(0))); |
|
525
|
|
|
|
|
|
|
char *addr = frame_ptr(state); |
|
526
|
|
|
|
|
|
|
unsigned int len; |
|
527
|
|
|
|
|
|
|
unsigned int snaplen; |
|
528
|
|
|
|
|
|
|
int mac; |
|
529
|
|
|
|
|
|
|
struct sockaddr_ll *sll; |
|
530
|
|
|
|
|
|
|
#if defined(HAVE_TPACKET2) |
|
531
|
|
|
|
|
|
|
struct tpacket2_hdr *hdr = (struct tpacket2_hdr *)addr; |
|
532
|
|
|
|
|
|
|
if((hdr->tp_status & 1) != 1) |
|
533
|
|
|
|
|
|
|
XSRETURN(0); |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
len = hdr->tp_len; |
|
536
|
|
|
|
|
|
|
snaplen = hdr->tp_snaplen; |
|
537
|
|
|
|
|
|
|
mac = hdr->tp_mac; |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
HVSTOREi(info, "tp_status", hdr->tp_status); |
|
540
|
|
|
|
|
|
|
HVSTOREi(info, "tp_len", hdr->tp_len); |
|
541
|
|
|
|
|
|
|
HVSTOREi(info, "tp_snaplen", hdr->tp_snaplen); |
|
542
|
|
|
|
|
|
|
HVSTOREi(info, "tp_sec", hdr->tp_sec); |
|
543
|
|
|
|
|
|
|
HVSTOREi(info, "tp_nsec", hdr->tp_nsec); |
|
544
|
|
|
|
|
|
|
HVSTOREi(info, "tp_vlan_tci", hdr->tp_vlan_tci); |
|
545
|
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
sll = (struct sockaddr_ll *)(addr + TPACKET_ALIGN(sizeof(struct tpacket2_hdr))); |
|
547
|
|
|
|
|
|
|
#elif defined(HAVE_TPACKET) |
|
548
|
|
|
|
|
|
|
struct tpacket_hdr *hdr = (struct tpacket_hdr *)addr; |
|
549
|
|
|
|
|
|
|
if((hdr->tp_status & 1) != 1) |
|
550
|
|
|
|
|
|
|
XSRETURN(0); |
|
551
|
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
len = hdr->tp_len; |
|
553
|
|
|
|
|
|
|
snaplen = hdr->tp_snaplen; |
|
554
|
|
|
|
|
|
|
mac = hdr->tp_mac; |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
HVSTOREi(info, "tp_status", hdr->tp_status); |
|
557
|
|
|
|
|
|
|
HVSTOREi(info, "tp_len", hdr->tp_len); |
|
558
|
|
|
|
|
|
|
HVSTOREi(info, "tp_snaplen", hdr->tp_snaplen); |
|
559
|
|
|
|
|
|
|
HVSTOREi(info, "tp_sec", hdr->tp_sec); |
|
560
|
|
|
|
|
|
|
HVSTOREi(info, "tp_nsec", hdr->tp_usec * 1000); |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
sll = (struct sockaddr_ll *)(addr + TPACKET_ALIGN(sizeof(struct tpacket_hdr))); |
|
563
|
|
|
|
|
|
|
#endif |
|
564
|
|
|
|
|
|
|
HVSTOREi(info, "sll_protocol", ntohs(sll->sll_protocol)); |
|
565
|
|
|
|
|
|
|
HVSTOREi(info, "sll_ifindex", sll->sll_ifindex); |
|
566
|
|
|
|
|
|
|
HVSTOREi(info, "sll_hatype", sll->sll_hatype); |
|
567
|
|
|
|
|
|
|
HVSTOREi(info, "sll_pkttype", sll->sll_pkttype); |
|
568
|
|
|
|
|
|
|
HVSTOREp(info, "sll_addr", sll->sll_addr, sll->sll_halen); |
|
569
|
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
/* Alias, don't copy data - we like zero-copy */ |
|
571
|
|
|
|
|
|
|
SvUPGRADE(buffer, SVt_PV); |
|
572
|
|
|
|
|
|
|
SvPVX(buffer) = addr + mac; |
|
573
|
|
|
|
|
|
|
SvCUR_set(buffer, snaplen); |
|
574
|
|
|
|
|
|
|
SvLEN_set(buffer, 0); |
|
575
|
|
|
|
|
|
|
SvPOK_only(buffer); |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
sv_setiv(ST(0), len); |
|
578
|
|
|
|
|
|
|
XSRETURN(1); |
|
579
|
|
|
|
|
|
|
} |
|
580
|
|
|
|
|
|
|
#else |
|
581
|
0
|
|
|
|
|
|
croak("get_ring_frame() not supported on this platform"); |
|
582
|
|
|
|
|
|
|
#endif |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
void |
|
585
|
|
|
|
|
|
|
done_ring_frame(sock) |
|
586
|
|
|
|
|
|
|
InputStream sock |
|
587
|
|
|
|
|
|
|
PPCODE: |
|
588
|
|
|
|
|
|
|
#ifdef HAVE_RX_RING |
|
589
|
|
|
|
|
|
|
{ |
|
590
|
|
|
|
|
|
|
struct packet_rxring_state *state = get_rxring_state((SV*)sv_2io(ST(0))); |
|
591
|
|
|
|
|
|
|
char *addr = frame_ptr(state); |
|
592
|
|
|
|
|
|
|
#if defined(HAVE_TPACKET2) |
|
593
|
|
|
|
|
|
|
struct tpacket2_hdr *hdr = (struct tpacket2_hdr *)addr; |
|
594
|
|
|
|
|
|
|
#elif defined(HAVE_TPACKET) |
|
595
|
|
|
|
|
|
|
struct tpacket_hdr *hdr = (struct tpacket_hdr *)addr; |
|
596
|
|
|
|
|
|
|
#endif |
|
597
|
|
|
|
|
|
|
hdr->tp_status = TP_STATUS_KERNEL; |
|
598
|
|
|
|
|
|
|
|
|
599
|
|
|
|
|
|
|
state->frame_idx = (state->frame_idx + 1) % state->frame_nr; |
|
600
|
|
|
|
|
|
|
} |
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
XSRETURN(0); |
|
603
|
|
|
|
|
|
|
#else |
|
604
|
0
|
|
|
|
|
|
croak("done_ring_frame() not supported on this platform"); |
|
605
|
|
|
|
|
|
|
#endif |