blob: bab77ca6e820e3ec9124fd267e1005173ee0ff8a [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
/*
* bcmtr_inband.c - In-band transport driver
*/
#include <bcmos_system.h>
#include <bcmtr_inband.h>
#include <sys/types.h>
#include <sys/socket.h>
typedef struct device_info
{
bcmos_ipv4_address remote_ip;
uint16_t remote_port;
uint8_t channel;
int tr_udp_sock;
} device_info;
static device_info dev_info[BCMTR_MAX_OLTS];
#define DEBUG_ONLY 0
/** Initialize in-band transport driver
* \returns: 0 in case of success or error code < 0
*/
bcmos_errno bcmtr_ib_init(void)
{
return BCM_ERR_OK;
}
/** Cleanup in-band transport driver
* \returns: 0 in case of success or error code < 0
*/
void bcmtr_ib_exit(void)
{
int i;
for (i=0; i<BCMTR_MAX_OLTS; i++)
{
bcmtr_ib_disconnect(i);
}
}
/* Receive packet */
static bcmos_errno _bcmtr_ib_rx(uint32_t device, int s, bcmos_buf **buf, uint8_t *ch)
{
struct sockaddr_in sa;
#if 0
struct iovec iov = {.iov_len = BCMTR_MAX_MTU_SIZE};
struct msghdr msg = {
.msg_iov = &iov, .msg_iovlen = 1,
.msg_name = &sa, .msg_namelen = sizeof(sa)
};
#endif
bcmos_buf *b;
ssize_t len;
b = bcmos_buf_alloc(BCMTR_MAX_MTU_SIZE);
if (!b)
{
bcmos_printf("%s: Failed to allocate buffer\n", __FUNCTION__);
return BCM_ERR_NOMEM;
}
#if 0
iov.iov_base = bcmos_buf_data(b);
#endif
memset(&sa, 0, sizeof(sa));
len = recv(s, bcmos_buf_data(b), BCMTR_MAX_MTU_SIZE, 0);
if (len <= 0)
{
bcmos_printf("%s: recvmsg() --> %d\n", __FUNCTION__, len);
bcmos_buf_free(b);
return BCM_ERR_COMM_FAIL;
}
*ch = dev_info[device].channel;
dev_info[device].channel = 0;
bcmos_buf_length_set(b, (int)len);
*buf = b;
#if DEBUG_ONLY
bcmos_printf("\nReceived to %d bytes from channel %d/%d port", len, *ch, sa.sin_port);
{
int ii = 0;
unsigned char *c = bcmos_buf_data(b);
int size = (int)len;
for (ii=0; ii<size; ii++)
{
if (0==(ii%16)) bcmos_printf("\n");
if (0==(ii%8)) bcmos_printf(" ");
bcmos_printf(" %02x", *c);
c++;
}
bcmos_printf("\n");
}
#endif
return BCM_ERR_OK;
}
/** Connect to maple device */
bcmos_errno bcmtr_ib_connect(uint8_t device, bcmos_ipv4_address ip_address, uint16_t udp_port)
{
int r = 0;
int s = 0;
struct sockaddr_in sa;
/*Check for valid device*/
BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
if (dev_info[device].tr_udp_sock)
return BCM_ERR_ALREADY;
dev_info[device].remote_ip = ip_address;
dev_info[device].remote_port = udp_port;
/*check that ip address and port have been initialized*/
if(dev_info[device].remote_port == 0 || dev_info[device].remote_ip.u32 == 0)
{
bcmos_printf("%s: IP address and port not initialized. Error %d\n", __FUNCTION__, r);
return BCM_ERR_RANGE;
}
/* Create socket */
s = socket(AF_INET, SOCK_DGRAM, 0);
if (!s)
{
bcmos_printf("%s: Failed to create socket. Error %d\n", __FUNCTION__, s);
return BCM_ERR_COMM_FAIL;
}
/* Connect to remote */
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = (in_port_t)htons(dev_info[device].remote_port);
sa.sin_addr.s_addr = (in_addr_t)htonl(dev_info[device].remote_ip.u32);
r = connect(s, (struct sockaddr*)&sa, sizeof(sa));
if (r)
{
bcmos_printf("%s: Failed to connect socket. Error %d\n", __FUNCTION__, r);
close(s);
return BCM_ERR_COMM_FAIL;
}
{
socklen_t slen;
if (getsockname(s, (struct sockaddr *)&sa, &slen) < 0)
{
bcmos_printf("%s: Connected socket invalid. Error %d\n", __FUNCTION__, r);
close(s);
return BCM_ERR_COMM_FAIL;
}
bcmos_printf("%s: device %d: socket (port %d) connected to %d.%d.%d.%d:%d\n",
__FUNCTION__, device, ntohs((uint16_t)sa.sin_port),
(int)(dev_info[device].remote_ip.u32 >> 24), (int)((dev_info[device].remote_ip.u32 >> 16) & 0xff),
(int)((dev_info[device].remote_ip.u32 >> 8) & 0xff), (int)(dev_info[device].remote_ip.u32 & 0xff),
(int)dev_info[device].remote_port);
}
dev_info[device].tr_udp_sock = s;
return BCM_ERR_OK;
}
/** Disconnect. All buffers are released
* \param[in] device Maple device index
* \returns: 0 in case of success or error code < 0
*/
bcmos_errno bcmtr_ib_disconnect(uint8_t device)
{
BUG_ON((unsigned)device >= BCMTR_MAX_OLTS);
bcmos_printf("%s: disconnecting %d..", __FUNCTION__, device);
if (dev_info[device].tr_udp_sock)
{
int s = dev_info[device].tr_udp_sock;
dev_info[device].tr_udp_sock = 0;
close(s);
}
bcmos_printf("done\n");
return BCM_ERR_OK;
}
/** Send packet to device via in-band interface
* \param[in] device Mapole device index
* \param[in] channel Logical channel
* \param[in] buf Buffer to be transmitted
* \returns: 0 in case of success or error code < 0
*/
bcmos_errno bcmtr_ib_send(uint8_t device, uint8_t channel, bcmos_buf *buf)
{
int buflen = bcmos_buf_length(buf);
struct iovec iov = { .iov_base = bcmos_buf_data(buf), .iov_len = buflen };
struct msghdr msg = {
.msg_iov = &iov, .msg_iovlen = 1, .msg_flags=MSG_DONTWAIT,
.msg_name = NULL, .msg_namelen = 0
};
ssize_t len;
dev_info[device].channel = channel;
len = sendmsg(dev_info[device].tr_udp_sock, &msg, 0);
if ((int)len < buflen)
{
bcmos_printf("%s: sendmsg(%u) --> %d\n", __FUNCTION__, buflen, len);
bcmos_buf_free(buf);
return BCM_ERR_NOT_CONNECTED;
}
#if 1
{
int ii = 0;
unsigned char *c = bcmos_buf_data(buf);
struct sockaddr_in sa;
socklen_t slen;
for (ii=0; ii<(int)len; ii++)
{
if (0==(ii%16)) bcmos_printf("\n");
if (0==(ii%8)) bcmos_printf(" ");
bcmos_printf(" %02x", *c);
c++;
}
if (getsockname(dev_info[device].tr_udp_sock, (struct sockaddr *)&sa, &slen) < 0)
{
bcmos_printf("%s: Connected socket invalid\n", __FUNCTION__);
return BCM_ERR_COMM_FAIL;
}
bcmos_printf("\nSent %d bytes to channel %d from port %d\t", len, channel, sa.sin_port);
}
#endif
return BCM_ERR_OK;
}
/* Receive packet from device */
bcmos_errno bcmtr_ib_receive(uint32_t device, uint8_t *channel, bcmos_buf **buf)
{
if (device >= BCMTR_MAX_OLTS || ! dev_info[device].tr_udp_sock)
{
return BCM_ERR_PARM;
}
return _bcmtr_ib_rx(device, dev_info[device].tr_udp_sock, buf, channel);
}