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 |