*
* @v iobuf I/O buffer
* @v tcpip_protocol Transport-layer protocol
+ * @v st_src Source address, or NULL to use default
* @v st_dest Destination address
* @v netdev Network device (or NULL to route automatically)
* @v trans_csum Transport-layer checksum to complete, or NULL
*/
int ( * tx ) ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip_protocol,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum );
extern int tcpip_rx ( struct io_buffer *iobuf, uint8_t tcpip_proto,
struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum );
-extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+extern int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum );
st_dest.sin6.sin6_addr.in6_u.u6_addr8[13] = 0xff;
/* Send packet over IP6 */
- return tcpip_tx ( iobuf, &icmp6_protocol, &st_dest.st,
+ return tcpip_tx ( iobuf, &icmp6_protocol, NULL, &st_dest.st,
NULL, &nsolicit->csum );
}
*
* @v iobuf I/O buffer
* @v tcpip Transport-layer protocol
+ * @v st_src Source network-layer address
* @v st_dest Destination network-layer address
* @v netdev Network device to use if no route found, or NULL
* @v trans_csum Transport-layer checksum to complete, or NULL
*/
static int ipv4_tx ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip_protocol,
+ struct sockaddr_tcpip *st_src,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum ) {
struct iphdr *iphdr = iob_push ( iobuf, sizeof ( *iphdr ) );
+ struct sockaddr_in *sin_src = ( ( struct sockaddr_in * ) st_src );
struct sockaddr_in *sin_dest = ( ( struct sockaddr_in * ) st_dest );
struct ipv4_miniroute *miniroute;
struct in_addr next_hop;
/* Use routing table to identify next hop and transmitting netdev */
next_hop = iphdr->dest;
- if ( ( miniroute = ipv4_route ( &next_hop ) ) ) {
+ if ( sin_src )
+ iphdr->src = sin_src->sin_addr;
+ if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
+ ( ! IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) &&
+ ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
iphdr->src = miniroute->address;
netdev = miniroute->netdev;
}
*/
static int ipv6_tx ( struct io_buffer *iobuf,
struct tcpip_protocol *tcpip,
+ struct sockaddr_tcpip *st_src __unused,
struct sockaddr_tcpip *st_dest,
struct net_device *netdev,
uint16_t *trans_csum ) {
DBGC ( tcp, "\n" );
/* Transmit packet */
- return tcpip_tx ( iobuf, &tcp_protocol, &tcp->peer, NULL,
+ return tcpip_tx ( iobuf, &tcp_protocol, NULL, &tcp->peer, NULL,
&tcphdr->csum );
}
DBGC ( tcp, "\n" );
/* Transmit packet */
- return tcpip_tx ( iobuf, &tcp_protocol, st_dest,
+ return tcpip_tx ( iobuf, &tcp_protocol, NULL, st_dest,
NULL, &tcphdr->csum );
}
*
* @v iobuf I/O buffer
* @v tcpip_protocol Transport-layer protocol
+ * @v st_src Source address, or NULL to use route default
* @v st_dest Destination address
* @v netdev Network device to use if no route found, or NULL
* @v trans_csum Transport-layer checksum to complete, or NULL
* @ret rc Return status code
*/
int tcpip_tx ( struct io_buffer *iobuf, struct tcpip_protocol *tcpip_protocol,
- struct sockaddr_tcpip *st_dest, struct net_device *netdev,
- uint16_t *trans_csum ) {
+ struct sockaddr_tcpip *st_src, struct sockaddr_tcpip *st_dest,
+ struct net_device *netdev, uint16_t *trans_csum ) {
struct tcpip_net_protocol *tcpip_net;
/* Hand off packet to the appropriate network-layer protocol */
tcpip_net < tcpip_net_protocols_end ; tcpip_net++ ) {
if ( tcpip_net->sa_family == st_dest->st_family ) {
DBG ( "TCP/IP sending %s packet\n", tcpip_net->name );
- return tcpip_net->tx ( iobuf, tcpip_protocol, st_dest,
- netdev, trans_csum );
+ return tcpip_net->tx ( iobuf, tcpip_protocol, st_src,
+ st_dest, netdev, trans_csum );
}
}
*
* @v udp UDP connection
* @v iobuf I/O buffer
- * @v src_port Source port, or 0 to use default
+ * @v src Source address, or NULL to use default
* @v dest Destination address, or NULL to use default
* @v netdev Network device, or NULL to use default
* @ret rc Return status code
*/
static int udp_tx ( struct udp_connection *udp, struct io_buffer *iobuf,
- unsigned int src_port, struct sockaddr_tcpip *dest,
+ struct sockaddr_tcpip *src, struct sockaddr_tcpip *dest,
struct net_device *netdev ) {
struct udp_header *udphdr;
size_t len;
}
/* Fill in default values if not explicitly provided */
- if ( ! src_port )
- src_port = udp->local.st_port;
+ if ( ! src )
+ src = &udp->local;
if ( ! dest )
dest = &udp->peer;
udphdr = iob_push ( iobuf, sizeof ( *udphdr ) );
len = iob_len ( iobuf );
udphdr->dest = dest->st_port;
- udphdr->src = src_port;
+ udphdr->src = src->st_port;
udphdr->len = htons ( len );
udphdr->chksum = 0;
udphdr->chksum = tcpip_chksum ( udphdr, len );
ntohs ( udphdr->len ) );
/* Send it to the next layer for processing */
- if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, dest, netdev,
+ if ( ( rc = tcpip_tx ( iobuf, &udp_protocol, src, dest, netdev,
&udphdr->chksum ) ) != 0 ) {
DBGC ( udp, "UDP %p could not transmit packet: %s\n",
udp, strerror ( rc ) );
struct xfer_metadata *meta ) {
struct udp_connection *udp =
container_of ( xfer, struct udp_connection, xfer );
- struct sockaddr_tcpip *src;
+ struct sockaddr_tcpip *src = NULL;
struct sockaddr_tcpip *dest = NULL;
struct net_device *netdev = NULL;
- unsigned int src_port = 0;
/* Apply xfer metadata */
if ( meta ) {
src = ( struct sockaddr_tcpip * ) meta->src;
- if ( src )
- src_port = src->st_port;
dest = ( struct sockaddr_tcpip * ) meta->dest;
netdev = meta->netdev;
}
/* Transmit data, if possible */
- udp_tx ( udp, iobuf, src_port, dest, netdev );
+ udp_tx ( udp, iobuf, src, dest, netdev );
return 0;
}