From 16f49728f1c8d6584efea4ec82ff97a896781bf0 Mon Sep 17 00:00:00 2001 From: "7u83@mail.ru" <7u83@mail.ru@noemail.net> Date: Sun, 10 Apr 2016 13:56:34 +0000 Subject: [PATCH] Inital commit FossilOrigin-Name: 16b834c98ef1efca7c945ad0470b2b6951b77adeff29056ef5318646650ed0b6 --- src/cw/netconn.c | 391 +++++++++++++++++++++++++++++++++++++++++++++++ src/cw/netconn.h | 64 ++++++++ 2 files changed, 455 insertions(+) create mode 100644 src/cw/netconn.c create mode 100644 src/cw/netconn.h diff --git a/src/cw/netconn.c b/src/cw/netconn.c new file mode 100644 index 00000000..b249682f --- /dev/null +++ b/src/cw/netconn.c @@ -0,0 +1,391 @@ +/* + This file is part of actube. + + actube is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + libcapwap is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar. If not, see . + +*/ + +#include +#include +#include + +#include "sock.h" +#include "netconn.h" +#include "log.h" +#include "dbg.h" +#include "capwap.h" +#include "cw.h" + +static int netconn_recv_packet_(struct netconn *nc, uint8_t * buf, int len, int flags) +{ + int n; + while ((n = recv(nc->sock, (char *) buf, len, flags)) < 0) { + if (errno != EINTR) { + if (errno == EAGAIN) + return n; + + } + } + return n; +} + +int netconn_recv_packet(struct netconn *nc, uint8_t * buf, int len) +{ + return netconn_recv_packet_(nc, buf, len, 0); +} + +int netconn_recv_packet_peek(struct netconn *nc, uint8_t * buf, int len) +{ + int rc = netconn_recv_packet_(nc, buf, len, MSG_PEEK); + return rc; + +} + +static uint8_t *netconn_q_get_packet(struct netconn *nc) +{ + struct timespec timespec; + clock_gettime(CLOCK_REALTIME, ×pec); + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + timespec.tv_sec++; + + /* wait one second to get a packet */ + if (sem_timedwait(&nc->q_sem, ×pec) == -1) { + return NULL; + }; + + int qrpos = nc->qrpos + 1; + if (qrpos == nc->qsize) + qrpos = 0; + nc->qrpos = qrpos; + return nc->q[qrpos]; +} + +static int netconn_q_recv_packet_(struct netconn *nc, uint8_t * buffer, int len, int peek) +{ + if (!nc->cur_packet) { + if ((nc->cur_packet = netconn_q_get_packet(nc)) == 0) { + errno = EAGAIN; + return -1; + } + nc->cur_packet_len = *((uint32_t *) nc->cur_packet); + nc->cur_packet_pos = 4; + } + + if (nc->cur_packet_len > len) { + memcpy(buffer, nc->cur_packet + nc->cur_packet_pos, len); + if (peek) + return len; + + nc->cur_packet_pos += len; + nc->cur_packet_len -= len; + if (nc->cur_packet_len == 0) { + free(nc->cur_packet); + nc->cur_packet = 0; + } + return len; + } + + memcpy(buffer, nc->cur_packet + nc->cur_packet_pos, nc->cur_packet_len); + if (peek) + return nc->cur_packet_len; + + free(nc->cur_packet); + nc->cur_packet = 0; + return nc->cur_packet_len; +} + +int netconn_q_recv_packet(struct netconn *nc, uint8_t * buffer, int len) +{ + return netconn_q_recv_packet_(nc, buffer, len, 0); +} + +int netconn_q_recv_packet_peek(struct netconn *nc, uint8_t * buffer, int len) +{ + return netconn_q_recv_packet_(nc, buffer, len, 1); +} + +void netconn_q_add_packet(struct netconn * nc,uint8_t *packet,int len) +{ + int qwpos = nc->qwpos; + if (qwpos==nc->qsize) + qwpos=0; + + if (nc->qrpos==qwpos){ + /* no buffers, discard packet */ + cw_dbg(DBG_PKT_ERR, "Discarding packet from %s, no queue buffers left", + sock_addr2str(&nc->addr)); + return; + } + + nc->q[qwpos]=malloc(len+4); + if (nc->q[qwpos]==NULL) + return; + + *((uint32_t*)(nc->q[qwpos]))=len; + memcpy(nc->q[qwpos]+4,packet,len); + nc->qwpos=qwpos+1; + + sem_post(&nc->q_sem); +} + + + + + + +void netconn_destroy(struct netconn *nc) +{ + if (!nc) + return; + + if (nc->fragman) + fragman_destroy(nc->fragman); + + if (nc->q) + free(nc->q); + + free(nc); +} + + +int netconn_send_packet(struct netconn *nc, const uint8_t * buffer, int len) +{ + int n; + while ((n = sendto(nc->sock, buffer, len, 0, + (struct sockaddr *) &nc->addr, + sock_addrlen((struct sockaddr *) &nc->addr))) < 0) { + + if (errno == EINTR) + continue; + + + return n; + } + + return n; +} + + + + +int netconn_send_capwap_msg(struct netconn * nc, uint8_t *rawmsg, int msglen) +{ + +// int msglen = cw_get_hdr_msg_total_len(rawmsg); + + + uint8_t * ptr = rawmsg; + + int fragoffset = 0; + + int hlen = cw_get_hdr_hlen(rawmsg)*4; + +// int mtu = nc->mtu; + + int mtu = 1400; + + while (msglen>mtu){ + cw_set_hdr_flags(rawmsg,CW_FLAG_HDR_F,1); + cw_put_dword(ptr+4, nc->fragid<<16 | fragoffset<<3 ); + + cw_dbg_pkt_nc(DBG_PKT_OUT,nc,ptr,mtu,(struct sockaddr*)&nc->addr); + + if (nc->write(nc,ptr,mtu)<0) + return -1; + + ptr +=mtu-hlen; + fragoffset+=(mtu-hlen)/8; + + msglen-=mtu-hlen; + + } + + + if (fragoffset) + cw_set_hdr_flags(rawmsg,CW_FLAG_HDR_F | CW_FLAG_HDR_L,1); + else + cw_set_hdr_flags(rawmsg,CW_FLAG_HDR_F,0); + + cw_put_dword(ptr+4, nc->fragid<<16 | fragoffset<<3 ); + + cw_dbg_pkt_nc(DBG_PKT_OUT,nc,ptr,msglen,(struct sockaddr*)&nc->addr); + + return nc->write(nc,ptr,msglen-0); +} + + + +int netconn_process_packet(struct netconn *nc, uint8_t * packet, int len, + struct sockaddr *from) +{ + + cw_dbg_pkt_nc(DBG_PKT_IN, nc, packet, len, from); + if (len < 8) { + /* packet too short */ + cw_dbg(DBG_PKT_ERR, + "Discarding packet from %s, packet too short, len=%d, at least 8 expected.", + sock_addr2str(&nc->addr), len); + errno = EAGAIN; + return -1; + } + + int preamble = cw_get_hdr_preamble(packet); + + if ((preamble & 0xf0) != (CAPWAP_VERSION << 4)) { + /* wrong version */ + cw_dbg(DBG_PKT_ERR, + "Discarding packet from %s, wrong version, version=%d, version %d expected.", + sock_addr2str(&nc->addr), (preamble & 0xf0) >> 4, + CAPWAP_VERSION); + errno = EAGAIN; + return -1; + } + + if (preamble & 0xf) { + /* Encrypted data, this shuold never happen here */ + cw_dbg(DBG_PKT_ERR, + "Discarding packet from %s, encrypted data after decryption ...", + sock_addr2str(&nc->addr)); + errno = EAGAIN; + return -1; + } + + + int offs = cw_get_hdr_msg_offset(packet); + + + int payloadlen = len - offs; + if (payloadlen < 0) { + /* Eleminate messages with wrong header size */ + cw_dbg(DBG_PKT_ERR, + "Discarding packet from %s, header length (%d) greater than packet len (%d).", + sock_addr2str(&nc->addr), offs, len); + errno = EAGAIN; + return -1; + } + + /* Check if Radio MAC is present */ + if (cw_get_hdr_flag_m(packet)) { + + if (cw_get_hdr_rmac_len(packet) + 8 > offs) { + /* wrong rmac size */ + cw_dbg(DBG_PKT_ERR, + "Discarding packet from %s, wrong R-MAC size, size=%d", + sock_addr2str(&nc->addr), *(packet + 8)); + errno = EAGAIN; + return -1; + } + + } + + + if (cw_get_hdr_flag_f(packet)) { + /* fragmented, add the packet to fragman */ + uint8_t *f; + f = fragman_add(nc->fragman, packet, offs, payloadlen); + if (f == NULL) { + errno = EAGAIN; + return -1; + } + + + cw_dbg_pkt_nc(DBG_PKT_IN, nc, f + 4, *(uint32_t *) f, from); + + // XXX: Modify fragman to not throw away CAPWAP headers + + int rc = nc->process_message(nc, f + 4, *(uint32_t *) f, from); + + free(f); + return rc; + } + + /* not fragmented, we have a complete message */ + + return nc->process_message(nc, packet, len, from); +} + + + +/** + * Used as main message loop + */ +int netconn_read_messages(struct netconn *nc) +{ + uint8_t buf[2024]; + int len = 2024; + + int n = nc->read(nc, buf, len); + if (n < 0) + return n; + + if (n > 0) { + return nc->process_packet(nc, buf, n, + (struct sockaddr *) &nc->addr); + } + errno = EAGAIN; + return -1; +} + + + + +/** + * Create a netconn object + */ +struct netconn *netconn_create(int sock, struct sockaddr *addr, int qsize) +{ + struct netconn *nc = malloc(sizeof(struct netconn)); + if (!nc) + return NULL; + + memset(nc, 0, sizeof(struct netconn)); + + nc->sock = sock; + sock_copyaddr(&nc->addr, addr); + + if (!qsize) { + nc->recv_packet = netconn_recv_packet; + nc->recv_packet_peek = netconn_recv_packet_peek; + goto finalize; + } + + + if (!(nc->q = malloc(sizeof(uint8_t *) * qsize))) { + netconn_destroy(nc); + return NULL; + } + nc->qrpos = -1; + if (sem_init(&nc->q_sem, 0, 0) != 0) { + cw_log(LOG_ERR, "Fatal- Can't init semaphore for conn object: %s", + strerror(errno)); + netconn_destroy(nc); + return NULL; + }; + + nc->recv_packet = netconn_q_recv_packet; + nc->recv_packet_peek = netconn_q_recv_packet_peek; + + finalize: + nc->send_packet = netconn_send_packet; + nc->write = nc->send_packet; + nc->read = nc->recv_packet; + + return nc; +} diff --git a/src/cw/netconn.h b/src/cw/netconn.h new file mode 100644 index 00000000..89bbae9c --- /dev/null +++ b/src/cw/netconn.h @@ -0,0 +1,64 @@ +#ifndef __CONN_LINK_H +#define __CONN_LINK_H + + +#include +#include +#include + +#include "fragman.h" + +struct netconn; + +struct netconn{ + + int sock; + struct sockaddr_storage addr; + + + + /** The framgent manager used on this connection */ + frag_t *fragman; + + + /** Current Fragment ID */ + int fragid; + + int (*recv_packet) (struct netconn *, uint8_t *, int); + int (*recv_packet_peek) (struct netconn *, uint8_t *, int); + int (*send_packet) (struct netconn *, const uint8_t *, int); + + int (*readfrom) (struct netconn *, uint8_t *, int, struct sockaddr_storage *); + int (*read) (struct netconn *, uint8_t *, int); + int (*write) (struct netconn *, const uint8_t *, int); + + + /* optional packet queue */ + uint8_t **q; + int qsize; + int qrpos; + int qwpos; + sem_t q_sem; + uint8_t *cur_packet; + int cur_packet_len; + int cur_packet_pos; + + int (*process_packet)(struct netconn *nc, uint8_t * packet, int len,struct sockaddr *from); + int (*process_message)(struct netconn *nc, uint8_t * rawmsg, int rawlen, + struct sockaddr *from); + + void * data; + +}; + +extern struct netconn * netconn_create(int sock, struct sockaddr * addr, int qsize); +extern void netconn_destroy(struct netconn *nc); +extern void netconn_q_add_packet(struct netconn * nc,uint8_t *packet,int len); +extern int netconn_process_packet(struct netconn *nc, uint8_t * packet, int len, + struct sockaddr *from); +extern int netconn_read_messages(struct netconn *nc); +extern int netconn_send_capwap_msg(struct netconn * nc, uint8_t *rawmsg, int msglen); + + + +#endif