Skip to content

Commit 72abe80

Browse files
committedDec 26, 2016
Factor out IpRepr into the wire module.
1 parent a713342 commit 72abe80

File tree

6 files changed

+196
-123
lines changed

6 files changed

+196
-123
lines changed
 

‎src/iface/ethernet.rs

+13-53
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ use Error;
55
use phy::Device;
66
use wire::{EthernetAddress, EthernetProtocol, EthernetFrame};
77
use wire::{ArpPacket, ArpRepr, ArpOperation};
8-
use wire::{IpAddress, IpProtocol};
9-
use wire::{Ipv4Address, Ipv4Packet, Ipv4Repr};
8+
use wire::{Ipv4Packet, Ipv4Repr};
109
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
10+
use wire::{IpAddress, IpProtocol, IpRepr};
1111
use wire::{TcpPacket, TcpRepr, TcpControl};
12-
use socket::{Socket, IpRepr};
12+
use socket::Socket;
1313
use super::{ArpCache};
1414

1515
/// An Ethernet network interface.
@@ -213,13 +213,8 @@ impl<'a, 'b: 'a,
213213
Ipv4Repr { src_addr, dst_addr, protocol } => {
214214
let mut handled = false;
215215
for socket in self.sockets.borrow_mut() {
216-
let ip_repr = IpRepr {
217-
src_addr: src_addr.into(),
218-
dst_addr: dst_addr.into(),
219-
protocol: protocol,
220-
payload: ipv4_packet.payload()
221-
};
222-
match socket.collect(&ip_repr) {
216+
let ip_repr = IpRepr::Ipv4(ipv4_repr);
217+
match socket.collect(&ip_repr, ipv4_packet.payload()) {
223218
Ok(()) => {
224219
// The packet was valid and handled by socket.
225220
handled = true;
@@ -370,62 +365,27 @@ impl<'a, 'b: 'a,
370365

371366
let mut nothing_to_transmit = true;
372367
for socket in self.sockets.borrow_mut() {
373-
let result = socket.dispatch(&mut |repr| {
374-
let src_addr =
375-
try!(match &repr.src_addr {
376-
&IpAddress::Unspecified |
377-
&IpAddress::Ipv4(Ipv4Address([0, _, _, _])) => {
378-
let mut assigned_addr = None;
379-
for addr in src_protocol_addrs {
380-
match addr {
381-
addr @ &IpAddress::Ipv4(_) => {
382-
assigned_addr = Some(addr);
383-
break
384-
}
385-
_ => ()
386-
}
387-
}
388-
assigned_addr.ok_or(Error::Unaddressable)
389-
},
390-
addr => Ok(addr)
391-
});
392-
393-
let ipv4_repr =
394-
match (src_addr, &repr.dst_addr) {
395-
(&IpAddress::Ipv4(src_addr),
396-
&IpAddress::Ipv4(dst_addr)) => {
397-
Ipv4Repr {
398-
src_addr: src_addr,
399-
dst_addr: dst_addr,
400-
protocol: repr.protocol
401-
}
402-
},
403-
_ => unreachable!()
404-
};
368+
let result = socket.dispatch(&mut |repr, payload| {
369+
let repr = try!(repr.lower(src_protocol_addrs));
405370

406371
let dst_hardware_addr =
407-
match arp_cache.lookup(&repr.dst_addr) {
372+
match arp_cache.lookup(&repr.dst_addr()) {
408373
None => return Err(Error::Unaddressable),
409374
Some(hardware_addr) => hardware_addr
410375
};
411376

412-
let tx_len = EthernetFrame::<&[u8]>::buffer_len(ipv4_repr.buffer_len() +
413-
repr.payload.buffer_len());
377+
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len() +
378+
payload.buffer_len());
414379
let mut tx_buffer = try!(device.transmit(tx_len));
415380
let mut frame = try!(EthernetFrame::new(&mut tx_buffer));
416381
frame.set_src_addr(src_hardware_addr);
417382
frame.set_dst_addr(dst_hardware_addr);
418383
frame.set_ethertype(EthernetProtocol::Ipv4);
419384

420-
let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
421-
ipv4_repr.emit(&mut ip_packet, repr.payload.buffer_len());
385+
repr.emit(frame.payload_mut(), payload.buffer_len());
422386

423-
repr.payload.emit(&mut IpRepr {
424-
src_addr: repr.src_addr,
425-
dst_addr: repr.dst_addr,
426-
protocol: repr.protocol,
427-
payload: ip_packet.payload_mut()
428-
});
387+
let mut ip_packet = try!(Ipv4Packet::new(frame.payload_mut()));
388+
payload.emit(&repr, ip_packet.payload_mut());
429389

430390
Ok(())
431391
});

‎src/socket/mod.rs

+6-16
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! size for a buffer, allocate it, and let the networking stack use it.
1212
1313
use Error;
14-
use wire::{IpAddress, IpProtocol};
14+
use wire::IpRepr;
1515

1616
mod udp;
1717
mod tcp;
@@ -52,12 +52,12 @@ impl<'a, 'b> Socket<'a, 'b> {
5252
/// is returned.
5353
///
5454
/// This function is used internally by the networking stack.
55-
pub fn collect(&mut self, repr: &IpRepr<&[u8]>) -> Result<(), Error> {
55+
pub fn collect(&mut self, ip_repr: &IpRepr, payload: &[u8]) -> Result<(), Error> {
5656
match self {
5757
&mut Socket::Udp(ref mut socket) =>
58-
socket.collect(repr),
58+
socket.collect(ip_repr, payload),
5959
&mut Socket::Tcp(ref mut socket) =>
60-
socket.collect(repr),
60+
socket.collect(ip_repr, payload),
6161
&mut Socket::__Nonexhaustive => unreachable!()
6262
}
6363
}
@@ -70,7 +70,7 @@ impl<'a, 'b> Socket<'a, 'b> {
7070
///
7171
/// This function is used internally by the networking stack.
7272
pub fn dispatch<F>(&mut self, emit: &mut F) -> Result<(), Error>
73-
where F: FnMut(&IpRepr<&IpPayload>) -> Result<(), Error> {
73+
where F: FnMut(&IpRepr, &IpPayload) -> Result<(), Error> {
7474
match self {
7575
&mut Socket::Udp(ref mut socket) =>
7676
socket.dispatch(emit),
@@ -81,16 +81,6 @@ impl<'a, 'b> Socket<'a, 'b> {
8181
}
8282
}
8383

84-
/// An IP packet representation.
85-
///
86-
/// This struct abstracts the various versions of IP packets.
87-
pub struct IpRepr<T> {
88-
pub src_addr: IpAddress,
89-
pub dst_addr: IpAddress,
90-
pub protocol: IpProtocol,
91-
pub payload: T
92-
}
93-
9484
/// An IP-encapsulated packet representation.
9585
///
9686
/// This trait abstracts the various types of packets layered under the IP protocol,
@@ -100,7 +90,7 @@ pub trait IpPayload {
10090
fn buffer_len(&self) -> usize;
10191

10292
/// Emit this high-level representation into a sequence of octets.
103-
fn emit(&self, repr: &mut IpRepr<&mut [u8]>);
93+
fn emit(&self, ip_repr: &IpRepr, payload: &mut [u8]);
10494
}
10595

10696
/// A conversion trait for network sockets.

‎src/socket/tcp.rs

+30-35
Original file line numberDiff line numberDiff line change
@@ -241,27 +241,27 @@ impl<'a> TcpSocket<'a> {
241241
}
242242

243243
/// See [Socket::collect](enum.Socket.html#method.collect).
244-
pub fn collect(&mut self, ip_repr: &IpRepr<&[u8]>) -> Result<(), Error> {
245-
if ip_repr.protocol != IpProtocol::Tcp { return Err(Error::Rejected) }
244+
pub fn collect(&mut self, ip_repr: &IpRepr, payload: &[u8]) -> Result<(), Error> {
245+
if ip_repr.protocol() != IpProtocol::Tcp { return Err(Error::Rejected) }
246246

247-
let packet = try!(TcpPacket::new(ip_repr.payload));
248-
let repr = try!(TcpRepr::parse(&packet, &ip_repr.src_addr, &ip_repr.dst_addr));
247+
let packet = try!(TcpPacket::new(payload));
248+
let repr = try!(TcpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
249249

250250
// Reject packets with a wrong destination.
251251
if self.local_endpoint.port != repr.dst_port { return Err(Error::Rejected) }
252252
if !self.local_endpoint.addr.is_unspecified() &&
253-
self.local_endpoint.addr != ip_repr.dst_addr { return Err(Error::Rejected) }
253+
self.local_endpoint.addr != ip_repr.dst_addr() { return Err(Error::Rejected) }
254254

255255
// Reject packets from a source to which we aren't connected.
256256
if self.remote_endpoint.port != 0 &&
257257
self.remote_endpoint.port != repr.src_port { return Err(Error::Rejected) }
258258
if !self.remote_endpoint.addr.is_unspecified() &&
259-
self.remote_endpoint.addr != ip_repr.src_addr { return Err(Error::Rejected) }
259+
self.remote_endpoint.addr != ip_repr.src_addr() { return Err(Error::Rejected) }
260260

261261
// Reject packets addressed to a closed socket.
262262
if self.state == State::Closed {
263263
net_trace!("tcp:{}:{}:{}: packet sent to a closed socket",
264-
self.local_endpoint, ip_repr.src_addr, repr.src_port);
264+
self.local_endpoint, ip_repr.src_addr(), repr.src_port);
265265
return Err(Error::Malformed)
266266
}
267267

@@ -315,8 +315,8 @@ impl<'a> TcpSocket<'a> {
315315
(State::Listen, TcpRepr {
316316
src_port, dst_port, control: TcpControl::Syn, seq_number, ack_number: None, ..
317317
}) => {
318-
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr, dst_port);
319-
self.remote_endpoint = IpEndpoint::new(ip_repr.src_addr, src_port);
318+
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), dst_port);
319+
self.remote_endpoint = IpEndpoint::new(ip_repr.src_addr(), src_port);
320320
self.local_seq_no = -seq_number; // FIXME: use something more secure
321321
self.remote_seq_no = seq_number + 1;
322322
self.set_state(State::SynReceived);
@@ -369,7 +369,7 @@ impl<'a> TcpSocket<'a> {
369369

370370
/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
371371
pub fn dispatch<F>(&mut self, emit: &mut F) -> Result<(), Error>
372-
where F: FnMut(&IpRepr<&IpPayload>) -> Result<(), Error> {
372+
where F: FnMut(&IpRepr, &IpPayload) -> Result<(), Error> {
373373
let mut repr = TcpRepr {
374374
src_port: self.local_endpoint.port,
375375
dst_port: self.remote_endpoint.port,
@@ -413,12 +413,12 @@ impl<'a> TcpSocket<'a> {
413413
_ => unreachable!()
414414
}
415415

416-
emit(&IpRepr {
416+
let ip_repr = IpRepr::Unspecified {
417417
src_addr: self.local_endpoint.addr,
418418
dst_addr: self.remote_endpoint.addr,
419419
protocol: IpProtocol::Tcp,
420-
payload: &repr as &IpPayload
421-
})
420+
};
421+
emit(&ip_repr, &repr)
422422
}
423423
}
424424

@@ -427,9 +427,9 @@ impl<'a> IpPayload for TcpRepr<'a> {
427427
self.buffer_len()
428428
}
429429

430-
fn emit(&self, repr: &mut IpRepr<&mut [u8]>) {
431-
let mut packet = TcpPacket::new(&mut repr.payload).expect("undersized payload");
432-
self.emit(&mut packet, &repr.src_addr, &repr.dst_addr)
430+
fn emit(&self, ip_repr: &IpRepr, payload: &mut [u8]) {
431+
let mut packet = TcpPacket::new(payload).expect("undersized payload");
432+
self.emit(&mut packet, &ip_repr.src_addr(), &ip_repr.dst_addr())
433433
}
434434
}
435435

@@ -486,37 +486,32 @@ mod test {
486486
let mut buffer = vec![0; repr.buffer_len()];
487487
let mut packet = TcpPacket::new(&mut buffer).unwrap();
488488
repr.emit(&mut packet, &REMOTE_IP, &LOCAL_IP);
489-
let result = $socket.collect(&IpRepr {
489+
let ip_repr = IpRepr::Unspecified {
490490
src_addr: REMOTE_IP,
491491
dst_addr: LOCAL_IP,
492-
protocol: IpProtocol::Tcp,
493-
payload: &packet.into_inner()[..]
494-
});
492+
protocol: IpProtocol::Tcp
493+
};
494+
let result = $socket.collect(&ip_repr, &packet.into_inner()[..]);
495495
result.expect("send error")
496496
})
497497
}
498498

499499
macro_rules! recv {
500500
($socket:ident, $expected:expr) => ({
501-
let result = $socket.dispatch(&mut |repr| {
502-
assert_eq!(repr.protocol, IpProtocol::Tcp);
503-
assert_eq!(repr.src_addr, LOCAL_IP);
504-
assert_eq!(repr.dst_addr, REMOTE_IP);
505-
506-
let mut buffer = vec![0; repr.payload.buffer_len()];
507-
repr.payload.emit(&mut IpRepr {
508-
src_addr: repr.src_addr,
509-
dst_addr: repr.dst_addr,
510-
protocol: repr.protocol,
511-
payload: &mut buffer[..]
512-
});
501+
let result = $socket.dispatch(&mut |ip_repr, payload| {
502+
assert_eq!(ip_repr.protocol(), IpProtocol::Tcp);
503+
assert_eq!(ip_repr.src_addr(), LOCAL_IP);
504+
assert_eq!(ip_repr.dst_addr(), REMOTE_IP);
505+
506+
let mut buffer = vec![0; payload.buffer_len()];
507+
payload.emit(&ip_repr, &mut buffer[..]);
513508
let packet = TcpPacket::new(&buffer[..]).unwrap();
514-
let repr = TcpRepr::parse(&packet, &repr.src_addr, &repr.dst_addr).unwrap();
515-
assert_eq!(repr, $expected);
509+
let repr = TcpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr());
510+
assert_eq!(repr, Ok($expected));
516511
Ok(())
517512
});
518513
assert_eq!(result, Ok(()));
519-
let result = $socket.dispatch(&mut |_repr| {
514+
let result = $socket.dispatch(&mut |_repr, _payload| {
520515
Ok(())
521516
});
522517
assert_eq!(result, Err(Error::Exhausted));

‎src/socket/udp.rs

+19-18
Original file line numberDiff line numberDiff line change
@@ -168,19 +168,19 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
168168
}
169169

170170
/// See [Socket::collect](enum.Socket.html#method.collect).
171-
pub fn collect(&mut self, ip_repr: &IpRepr<&[u8]>) -> Result<(), Error> {
172-
if ip_repr.protocol != IpProtocol::Udp { return Err(Error::Rejected) }
171+
pub fn collect(&mut self, ip_repr: &IpRepr, payload: &[u8]) -> Result<(), Error> {
172+
if ip_repr.protocol() != IpProtocol::Udp { return Err(Error::Rejected) }
173173

174-
let packet = try!(UdpPacket::new(ip_repr.payload));
175-
let repr = try!(UdpRepr::parse(&packet, &ip_repr.src_addr, &ip_repr.dst_addr));
174+
let packet = try!(UdpPacket::new(payload));
175+
let repr = try!(UdpRepr::parse(&packet, &ip_repr.src_addr(), &ip_repr.dst_addr()));
176176

177177
if repr.dst_port != self.endpoint.port { return Err(Error::Rejected) }
178178
if !self.endpoint.addr.is_unspecified() {
179-
if self.endpoint.addr != ip_repr.dst_addr { return Err(Error::Rejected) }
179+
if self.endpoint.addr != ip_repr.dst_addr() { return Err(Error::Rejected) }
180180
}
181181

182182
let packet_buf = try!(self.rx_buffer.enqueue());
183-
packet_buf.endpoint = IpEndpoint { addr: ip_repr.src_addr, port: repr.src_port };
183+
packet_buf.endpoint = IpEndpoint { addr: ip_repr.src_addr(), port: repr.src_port };
184184
packet_buf.size = repr.payload.len();
185185
packet_buf.as_mut()[..repr.payload.len()].copy_from_slice(repr.payload);
186186
net_trace!("udp:{}:{}: collect {} octets",
@@ -190,20 +190,21 @@ impl<'a, 'b> UdpSocket<'a, 'b> {
190190

191191
/// See [Socket::dispatch](enum.Socket.html#method.dispatch).
192192
pub fn dispatch<F>(&mut self, emit: &mut F) -> Result<(), Error>
193-
where F: FnMut(&IpRepr<&IpPayload>) -> Result<(), Error> {
193+
where F: FnMut(&IpRepr, &IpPayload) -> Result<(), Error> {
194194
let packet_buf = try!(self.tx_buffer.dequeue());
195195
net_trace!("udp:{}:{}: dispatch {} octets",
196196
self.endpoint, packet_buf.endpoint, packet_buf.size);
197-
emit(&IpRepr {
197+
let ip_repr = IpRepr::Unspecified {
198198
src_addr: self.endpoint.addr,
199199
dst_addr: packet_buf.endpoint.addr,
200-
protocol: IpProtocol::Udp,
201-
payload: &UdpRepr {
202-
src_port: self.endpoint.port,
203-
dst_port: packet_buf.endpoint.port,
204-
payload: &packet_buf.as_ref()[..]
205-
} as &IpPayload
206-
})
200+
protocol: IpProtocol::Udp
201+
};
202+
let payload = UdpRepr {
203+
src_port: self.endpoint.port,
204+
dst_port: packet_buf.endpoint.port,
205+
payload: &packet_buf.as_ref()[..]
206+
};
207+
emit(&ip_repr, &payload)
207208
}
208209
}
209210

@@ -212,9 +213,9 @@ impl<'a> IpPayload for UdpRepr<'a> {
212213
self.buffer_len()
213214
}
214215

215-
fn emit(&self, repr: &mut IpRepr<&mut [u8]>) {
216-
let mut packet = UdpPacket::new(&mut repr.payload).expect("undersized payload");
217-
self.emit(&mut packet, &repr.src_addr, &repr.dst_addr)
216+
fn emit(&self, repr: &IpRepr, payload: &mut [u8]) {
217+
let mut packet = UdpPacket::new(payload).expect("undersized payload");
218+
self.emit(&mut packet, &repr.src_addr(), &repr.dst_addr())
218219
}
219220
}
220221

‎src/wire/ip.rs

+127-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::fmt;
22

3-
use super::Ipv4Address;
3+
use Error;
4+
use super::{Ipv4Address, Ipv4Packet, Ipv4Repr};
45

56
enum_with_unknown! {
67
/// Internetworking protocol.
@@ -98,6 +99,131 @@ impl fmt::Display for Endpoint {
9899
}
99100
}
100101

102+
/// An IP packet representation.
103+
///
104+
/// This enum abstracts the various versions of IP packets. It either contains a concrete
105+
/// high-level representation for some IP protocol version, or an unspecified representation,
106+
/// which permits the `IpAddress::Unspecified` addresses.
107+
#[derive(Debug, Clone)]
108+
pub enum IpRepr {
109+
Unspecified {
110+
src_addr: Address,
111+
dst_addr: Address,
112+
protocol: Protocol
113+
},
114+
Ipv4(Ipv4Repr),
115+
#[doc(hidden)]
116+
__Nonexhaustive
117+
}
118+
119+
impl IpRepr {
120+
/// Return the source address.
121+
pub fn src_addr(&self) -> Address {
122+
match self {
123+
&IpRepr::Unspecified { src_addr, .. } => src_addr,
124+
&IpRepr::Ipv4(repr) => Address::Ipv4(repr.src_addr),
125+
&IpRepr::__Nonexhaustive => unreachable!()
126+
}
127+
}
128+
129+
/// Return the destination address.
130+
pub fn dst_addr(&self) -> Address {
131+
match self {
132+
&IpRepr::Unspecified { dst_addr, .. } => dst_addr,
133+
&IpRepr::Ipv4(repr) => Address::Ipv4(repr.dst_addr),
134+
&IpRepr::__Nonexhaustive => unreachable!()
135+
}
136+
}
137+
138+
/// Return the protocol.
139+
pub fn protocol(&self) -> Protocol {
140+
match self {
141+
&IpRepr::Unspecified { protocol, .. } => protocol,
142+
&IpRepr::Ipv4(repr) => repr.protocol,
143+
&IpRepr::__Nonexhaustive => unreachable!()
144+
}
145+
}
146+
147+
/// Convert an unspecified representation into a concrete one, or return
148+
/// `Err(Error::Unaddressable)` if not possible.
149+
///
150+
/// # Panics
151+
/// This function panics if source and destination addresses belong to different families,
152+
/// or the destination address is unspecified, since this indicates a logic error.
153+
pub fn lower(&self, fallback_src_addrs: &[Address]) -> Result<IpRepr, Error> {
154+
match self {
155+
&IpRepr::Unspecified {
156+
src_addr: Address::Ipv4(src_addr),
157+
dst_addr: Address::Ipv4(dst_addr),
158+
protocol
159+
} => {
160+
Ok(IpRepr::Ipv4(Ipv4Repr {
161+
src_addr: src_addr,
162+
dst_addr: dst_addr,
163+
protocol: protocol
164+
}))
165+
}
166+
167+
&IpRepr::Unspecified {
168+
src_addr: Address::Unspecified,
169+
dst_addr: Address::Ipv4(dst_addr),
170+
protocol
171+
} => {
172+
let mut src_addr = None;
173+
for addr in fallback_src_addrs {
174+
match addr {
175+
&Address::Ipv4(addr) => {
176+
src_addr = Some(addr);
177+
break
178+
}
179+
_ => ()
180+
}
181+
}
182+
Ok(IpRepr::Ipv4(Ipv4Repr {
183+
src_addr: try!(src_addr.ok_or(Error::Unaddressable)),
184+
dst_addr: dst_addr,
185+
protocol: protocol
186+
}))
187+
}
188+
189+
&IpRepr::Unspecified { dst_addr: Address::Unspecified, .. } =>
190+
panic!("unspecified destination IP address"),
191+
// &IpRepr::Unspecified { .. } =>
192+
// panic!("source and destination IP address families do not match"),
193+
194+
repr @ &IpRepr::Ipv4(_) => Ok(repr.clone()),
195+
&IpRepr::__Nonexhaustive => unreachable!()
196+
}
197+
}
198+
199+
/// Return the length of a header that will be emitted from this high-level representation.
200+
///
201+
/// # Panics
202+
/// This function panics if invoked on an unspecified representation.
203+
pub fn buffer_len(&self) -> usize {
204+
match self {
205+
&IpRepr::Unspecified { .. } => panic!("unspecified IP representation"),
206+
&IpRepr::Ipv4(repr) => repr.buffer_len(),
207+
&IpRepr::__Nonexhaustive => unreachable!()
208+
}
209+
}
210+
211+
/// Emit this high-level representation into a buffer.
212+
///
213+
/// # Panics
214+
/// This function panics if invoked on an unspecified representation.
215+
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, buffer: T, payload_len: usize) {
216+
match self {
217+
&IpRepr::Unspecified { .. } => panic!("unspecified IP representation"),
218+
&IpRepr::Ipv4(repr) => {
219+
let mut packet = Ipv4Packet::new(buffer).expect("undersized buffer");
220+
repr.emit(&mut packet, payload_len)
221+
}
222+
&IpRepr::__Nonexhaustive => unreachable!()
223+
}
224+
}
225+
}
226+
101227
pub mod checksum {
102228
use byteorder::{ByteOrder, NetworkEndian};
103229

‎src/wire/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub use self::arp::Repr as ArpRepr;
102102
pub use self::ip::Protocol as IpProtocol;
103103
pub use self::ip::Address as IpAddress;
104104
pub use self::ip::Endpoint as IpEndpoint;
105+
pub use self::ip::IpRepr as IpRepr;
105106

106107
pub use self::ipv4::Address as Ipv4Address;
107108
pub use self::ipv4::Packet as Ipv4Packet;

0 commit comments

Comments
 (0)
Please sign in to comment.