Update of /cvsroot/linux-atm/linux-atm/src/mpoad In directory usw-pr-cvs1:/tmp/cvs-serv10656/mpoad Added Files: Tag: V2_4_0 TODO io.c io.h CHANGELOG Makefile.am k_interf.c k_interf.h get_vars.c get_vars.h lecs.c lecs.h main.c mpcd.8 tag_list.c README.mpoa packets.h p_factory.c p_recogn.c poll2select.c poll2select.h id_list.c Log Message: --- NEW FILE: TODO --- Check that closing unused SVCs does not create synchronization problems Get configuration information from LECS MPOA spec, A.1.4, IP Options, check them Support more MPOA/NHRP CIE error codes Check CBR vs UBR SVCs before using them as return channel Decide what to do when a new MPS is detected --- NEW FILE: io.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <unistd.h> #include <time.h> /* for time() */ #include <fcntl.h> #include <string.h> /* for strerror() */ #include <errno.h> #include <sys/ioctl.h> #include <sys/param.h> /* for OPEN_MAX */ #if __GLIBC__ >= 2 #include <sys/poll.h> #else /* ugly hack to make it compile on RH 4.2 - WA */ #include <syscall.h> #include <linux/poll.h> #define SYS_poll 168 _syscall3(int,poll,struct pollfd *,ufds,unsigned int,nfds,int,timeout); #endif #include <atm.h> #include <linux/atmioc.h> #include <linux/atmmpc.h> #include <sys/types.h> #include <sys/socket.h> #include <atm.h> #include <netinet/in.h> /* for ntohl() */ #include "packets.h" #include "k_interf.h" #include "io.h" #include "get_vars.h" #ifdef BROKEN_POLL #include "poll2select.h" #endif #ifndef OPEN_MAX /* Fixme: there's got to be a better way to fix this */ #define OPEN_MAX 256 #endif #define POLL_TIMEOUT 5000 /* poll() timeout, 5 seconds */ #if 1 #define dprintf printf #else #define dprintf(format,args...) #endif #if 0 #define ddprintf printf #else #define ddprintf(format,args...) #endif extern struct mpc_control mpc_control; /* from main.c */ int keep_alive_sm_running = 0; struct outgoing_shortcut { int fd; uint32_t ipaddr; /* in network byte order */ int state; /* see io.h for states */ }; static struct llc_snap_hdr llc_snap_mpoa_ctrl = { 0xaa, 0xaa, 0x03, {0x00, 0x00, 0x5e}, {0x00, 0x03} }; static time_t stay_alive; /* Next Keep-Alive should come before we hit this time */ static struct pollfd fds[OPEN_MAX]; static int first_empty; /* first non-reserved slot in fds[] */ static int fds_used; /* first non-occupied slot in fds[], => also # of used fds */ static short socket_type[OPEN_MAX]; /* type and state info for fds[], see "io.h" for types */ static struct outgoing_shortcut ingress_shortcuts[OPEN_MAX]; /* array of shortcuts we made */ static int update_ingress_entry(uint32_t *addr, int fd, int new_state); static int msg_from_mps(int slot); static int accept_conn(int slot); static int add_shortcut(int slot, int type); static int check_connection(int slot); static int complete_connection(int slot); static int create_shortcut(char *atm_addr,struct atm_qos qos); static void wait_for_mps_ctrl_addr(void); static int connect_to_MPS(void); void main_loop(int listen_socket) { int i, changed_fds; int kernel_ok, mps_ok, new_ctrl, new_shortcut; int poll_timeout = POLL_TIMEOUT; time_t now, previous_now; for (i = 0; i < OPEN_MAX; i++) fds[i].fd = -1; fds[0].fd = mpc_control.kernel_socket; /* mpcd <--> kernel socket */ fds[0].events = POLLIN; socket_type[0]= KERNEL; if(!mpc_control.mps_ctrl_addr_set) /* Can't do much without the MPS control ATM addr */ wait_for_mps_ctrl_addr(); connect_to_MPS(); fds[1].fd = mpc_control.MPS_socket; /* we opened this to MPS */ fds[1].events = POLLIN; socket_type[1]= (OUTGOING_CTRL | CONNECTED); fds[2].fd = mpc_control.MPS_listen_socket; /* for incoming control calls */ fds[2].events = POLLIN; socket_type[2]= LISTENING_CTRL; fds[3].fd = listen_socket; /* for incoming shortcuts */ fds[3].events = POLLIN; socket_type[3]= LISTENING_DATA; fds_used = first_empty = 4; now = previous_now = time(NULL); while (1) { kernel_ok = mps_ok = new_ctrl = new_shortcut = 1; fflush(stdout); #ifdef BROKEN_POLL changed_fds = poll2select(fds, fds_used, poll_timeout); #else changed_fds = poll(fds, fds_used, poll_timeout); #endif #if 0 printf("\nio.c: main_loop() poll returns %d\n", changed_fds); for (i = 0; i < OPEN_MAX; i++) { if (fds[i].fd < 0 ) continue; /* slot not in use */ if ( fds[i].revents == 0) { printf("check1: fd %d slot %d not changed\n", fds[i].fd, i); } else printf("check1: fd %d slot %d changed\n", fds[i].fd, i); } #endif switch(changed_fds) { case -1: printf("mpcd: io.c: main_loop: poll error: %s\n", strerror(errno)); if(errno == EINTR) continue; goto out; /* return to main() */ break; /* not reached */ case 0: keep_alive_sm(0, -1); /* (keepalive_liftime, seq_num) */ clear_expired(); /* id_list.c */ poll_timeout = POLL_TIMEOUT; previous_now = time(NULL); continue; break; /* not reached */ } /* It was not a timeout. Adjust poll_timeout */ now = time(NULL); poll_timeout -= now - previous_now; if (poll_timeout < 0) poll_timeout = 0; /* Since we are here something happened to the fds */ if (fds[0].revents) { dprintf("mpcd: io.c: main_loop() msg_from_kernel\n"); kernel_ok = msg_from_kernel(fds[0].fd); changed_fds--; } if (fds[1].revents) { ddprintf("mpcd: io.c: main_loop() msg_from_mps1\n"); mps_ok = msg_from_mps(1); changed_fds--; } if (fds[2].revents) { new_ctrl = accept_conn(2); changed_fds--; if( new_ctrl < 0 ) break; socket_type[new_ctrl] = INCOMING_CTRL | CONNECTED; dprintf("mpcd: io.c main_loop() accepted INCOMING_CTRL slot %d\n", new_ctrl); } if (fds[3].revents) { new_shortcut = accept_conn(3); dprintf("mpcd: io.c main_loop() accepted INCOMING_SHORTCUT slot %d\n", new_shortcut); changed_fds--; if( new_shortcut < 0 ) break; socket_type[new_shortcut] = INCOMING_SHORTCUT; if (add_shortcut(new_shortcut, MPC_SOCKET_EGRESS) < 0) break; } #if 0 if (changed_fds == 0) /* see if we can already go back to poll() */ continue; #endif for (i = first_empty; i < fds_used; i++) { if (fds[i].fd < 0 ) continue; /* slot not in use */ if ( fds[i].revents == 0) { ddprintf("fd %d slot %d not changed\n", fds[i].fd, i); continue; } ddprintf("about to process fd %d slot %d\n", fds[i].fd, i); if (socket_type[i] & INCOMING_CTRL) { ddprintf("mpcd: io.c: main_loop() msg_from_mps2\n"); mps_ok = msg_from_mps(i); } else { ddprintf("mpcd: io.c: main_loop() checking connection fd %d\n", fds[i].fd); if (check_connection(i) < 0) { printf("mpcd: io.c: main_loop: check_connection returned < 0\n"); break; /* this will cause break from while(1) too */ } } if (--changed_fds == 0) break; /* no more changed fds, leave for() */ } if (changed_fds != 0){ printf("mpcd: changed_fds = %d\n", changed_fds); /* break; */ /* leave while(1) */ } if (kernel_ok && mps_ok >= 0 && new_ctrl >= 0 && new_shortcut >= 0) continue; /* back to poll() */ else break; /* leave main_loop */ } out: /* clean up, close the sockets */ for (i = 0; i < fds_used; i++) { if (fds[i].fd < 0) continue; close(fds[i].fd); socket_type[i] = NOT_USED; } printf("mpcd: io.c: exiting main_loop()\n"); return; } /* * If MPS control ATM address is not given as an argument this func waits until * kernel has found one from a TLV in le_arp and tells us what it is. */ static void wait_for_mps_ctrl_addr(){ while(!mpc_control.mps_ctrl_addr_set){ #ifdef BROKEN_POLL if(poll2select(fds, 1, -1)) #else if(poll(fds, 1, -1)) #endif msg_from_kernel(fds[0].fd); } return; } /* * Sends a packet to MPS. Adds LLC/SNAP encapsulation * in the beginning of the buffer. */ int send_to_mps(char *buff, int length) { char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; int bytes_written; char *pos = tmp; if(mpc_control.MPS_socket<0){ connect_to_MPS(); fds[1].fd = mpc_control.MPS_socket; fds[1].events = POLLIN; fds[1].revents = 0; socket_type[1] = (OUTGOING_CTRL | CONNECTED); } memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); pos += sizeof(struct llc_snap_hdr); memcpy(pos, buff, length); length += sizeof(struct llc_snap_hdr); bytes_written = write(mpc_control.MPS_socket, tmp, length); while(bytes_written != 0){ bytes_written = write(mpc_control.MPS_socket, tmp+bytes_written, length-bytes_written); if( bytes_written < 0 ){ printf("mpcd: io.c: send_to_mps() write failed\n"); return -1; } } return 1; } /* * Sends a control packet over a shortcut. Used in a dataplane purge. */ int send_to_dataplane(char *buff, int length, int shortcut_fd) { char tmp[MAX_PACKET_LENGTH + sizeof(struct llc_snap_hdr)]; int bytes_written; char *pos = tmp; memcpy(pos, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)); pos += sizeof(struct llc_snap_hdr); memcpy(pos, buff, length); length += sizeof(struct llc_snap_hdr); bytes_written = write(shortcut_fd, tmp, length); while(bytes_written != 0){ bytes_written = write(shortcut_fd, tmp+bytes_written, length-bytes_written); if( bytes_written < 0 ){ printf("mpcd: io.c: write to dataplane failed\n"); return -1; } } return 1; } /* * Keep alive state machine. Sequence number less than * and keep_alive_lifetime equal to zero is used * when checking wheter the MPS is still alive. * */ void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number){ struct k_message msg; static unsigned previous_sequence_number = 0; static int start_keep_alive_sm = 0; time_t now = time(NULL); memset(&msg,0,sizeof(struct k_message)); if(!keep_alive_sm_running){ start_keep_alive_sm = 0; return; } if(!start_keep_alive_sm){ dprintf("mpcd: io.c: starting keep_alive_sm.\n"); stay_alive = time(NULL) + MPC_C2; start_keep_alive_sm = 1; return; } if( now > stay_alive ){ dprintf("mpcd: io.c: MPS death!"); msg.type = MPS_DEATH; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); send_to_kernel(&msg); previous_sequence_number = 0; stay_alive = now + MPC_C2; return; } if( sequence_number < 0 ) return; if( sequence_number < previous_sequence_number ){ dprintf("mpcd: io.c: MPS death!"); msg.type = MPS_DEATH; memcpy(msg.MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); send_to_kernel(&msg); previous_sequence_number = 0; stay_alive = now + MPC_C2; return; } stay_alive = now + keep_alive_lifetime; previous_sequence_number = sequence_number; return; } /* * Creates a socket, sets traffic and sap parameters * and binds the socket with given address. * * returns < 0 for error, socket for ok */ int get_socket(struct sockaddr_atmsvc *address) { struct atm_qos qos; struct atm_sap sap; int socket_fd; socket_fd = socket(PF_ATMSVC, SOCK_DGRAM, 0); if( socket_fd < 0 ){ printf("mpcd: io.c: socket creation failure: %s \n",strerror(errno)); return -1; } memset(&qos, 0, sizeof(qos)); memset(&sap, 0, sizeof(sap)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1536; qos.rxtp.max_sdu = 1536; sap.blli[0].l2_proto = ATM_L2_ISO8802; if (setsockopt(socket_fd, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: setsockopt SO_ATMQOS failed: %s \n",strerror(errno)); close(socket_fd); return -1; } if (setsockopt(socket_fd,SOL_ATM,SO_ATMSAP,&sap,sizeof(sap)) < 0) { printf("mpcd: io.c: setsockop SO_ATMSAP failed\n"); close (socket_fd); return -1; } if (address == NULL) return socket_fd; if (bind(socket_fd, (struct sockaddr *)address, sizeof(struct sockaddr_atmsvc)) < 0){ printf("mpcd: io.c: bind failure: %s \n",strerror(errno)); close(socket_fd); return -1; } return socket_fd; } /* * Creates an ATM_ANYCLASS traffic class socket, sets traffic and sap * parameters and binds the socket with given address. * * returns < 0 for error, socket for ok */ int get_listen_socket(struct sockaddr_atmsvc *address) { int s; struct atm_qos qos; s = get_socket(NULL); if (s < 0) { printf("mpcd: io.c: get_listen_socket() get socket failed\n"); return s; } memset(&qos, 0, sizeof(qos)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_ANYCLASS; qos.rxtp.traffic_class = ATM_ANYCLASS; if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: get_listen_socket() setsockopt SO_ATMQOS: %s\n", strerror(errno)); close(s); return -1; } if (bind(s, (struct sockaddr *)address, sizeof(struct sockaddr_atmsvc)) < 0){ printf("mpcd: io.c: get_listen_socket() bind: %s\n", strerror(errno)); close(s); return -1; } if (listen(s, 5) < 0) { printf("mpcd: io.c: get_lilsten_socket() listen: %s\n", strerror(errno)); close(s); return -1; } return s; } /* * If addr != NULL searches by addr. If addr == NULL searches by fd. * Returns ipaddr. * */ static int update_ingress_entry(uint32_t *addr, int fd, int new_state) { int i; if (addr != NULL) { dprintf("mpcd: io.c update_ingress_entry() updating ip 0x%x\n", *addr); for (i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].ipaddr == *addr) break; } else { dprintf("mpcd: io.c update_ingress_entry() updating fd %d\n", fd); for (i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].fd == fd) break; } if (i == OPEN_MAX) { printf("mpcd: io.c: update_ingress_entry: entry not found\n"); return 0; } ingress_shortcuts[i].fd = fd; ingress_shortcuts[i].state = new_state; if (new_state == INGRESS_NOT_USED) memset(&ingress_shortcuts[i], 0 , sizeof(ingress_shortcuts[i])); return ingress_shortcuts[i].ipaddr; } /* * returns < 0 for error * */ static int msg_from_mps(int slot) { int bytes_read, fd; char buff[MAX_PACKET_LENGTH]; fd = fds[slot].fd; bytes_read = read(fd, buff, sizeof(buff)); if (bytes_read < 0) { printf("mpcd: io.c: read failed from MPS: %s\n", strerror(errno)); close(fd); fds[slot].fd = -1; socket_type[slot] = NOT_USED; return -1; } if (bytes_read == 0) { dprintf("mpcd: io.c: EOF from MPS\n"); close(fd); fds[slot].fd = -1; if (slot == 1) mpc_control.MPS_socket = -1; socket_type[slot] = NOT_USED; return 1; /* See spec 4.6. Might be normal */ } if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) != 0 ) { printf("mpcd: io.c: msg_from_mps: MPS is pushing us garbage\n"); return -1; } (void)recognize_packet(buff + sizeof(struct llc_snap_hdr)); return 0; } /* * returns < 0 for error, slot of the new socket for ok * */ static int accept_conn(int slot) { struct sockaddr_atmsvc sa; int i, new_fd, sa_len; sa_len = sizeof(sa); new_fd = accept(fds[slot].fd, (struct sockaddr *)&sa, &sa_len); if (new_fd < 0) { printf("mpcd: io.c: accept_conn: %s\n", strerror(errno)); return -1; } for (i = first_empty; i < OPEN_MAX; i++) { if (fds[i].fd >= 0) /* slot in use ? */ continue; fds[i].fd = new_fd; fds[i].events = POLLIN; fds[i].revents = 0; break; } if (i == OPEN_MAX) { printf("mpcd: io.c: accept_conn: no room for new connection\n"); return -1; } if (i >= fds_used) fds_used = i + 1; return i; } /* * returns < 0 for error, slot of the new socket for ok * */ static int add_shortcut(int slot, int type) { struct atmmpc_ioc ioc_data; int ipaddr = 0; if (type == MPC_SOCKET_INGRESS) ipaddr = update_ingress_entry(NULL, fds[slot].fd, INGRESS_CONNECTED); ioc_data.dev_num = mpc_control.INTERFACE_NUMBER; ioc_data.ipaddr = ipaddr; ioc_data.type = type; if (ioctl(fds[slot].fd, ATMMPC_DATA, &ioc_data) < 0) { printf("mpcd: io.c: add_shortcut: %s\n", strerror(errno)); close(fds[slot].fd); fds[slot].fd = -1; socket_type[slot] = NOT_USED; return -1; } return slot; } /* * ECONNRESET == RST in TCP world. Check what equivalent * events can happen in ATM world. * * Returns < 0 for error */ static int check_connection(int slot) { char buff[MAX_PACKET_LENGTH]; struct k_message *msg; struct pollfd *pfd; int bytes_read; dprintf("mpcd: io.c: check_connection() event in fd %d, type %d\n", fds[slot].fd, socket_type[slot]); if (socket_type[slot] & CONNECTING) { /* connect() completed (maybe) */ complete_connection(slot); /* ignore return value */ return 0; } pfd = &fds[slot]; bytes_read = read(pfd->fd, buff, sizeof(buff)); if (bytes_read < 0) { if (errno == ECONNRESET || errno == EPIPE) { /* conn reset by the other end or kernel (EPIPE) */ if (socket_type[slot] & OUTGOING_SHORTCUT) update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); close(pfd->fd); pfd->fd = -1; socket_type[slot] = NOT_USED; return 1; } printf("mpcd: io.c: check_connection() bytes_read=%d, errno='%s'\n", bytes_read, strerror(errno)); return -1; } if (bytes_read == 0) { /* conn closed by the other end */ if (socket_type[slot] & OUTGOING_SHORTCUT) update_ingress_entry(NULL, pfd->fd, INGRESS_NOT_USED); dprintf("mpcd: io.c: check_connection() fd %d type %d; connection closed'\n", pfd->fd, socket_type[slot]); close(pfd->fd); pfd->fd = -1; socket_type[slot] = NOT_USED; return 1; } /* See if this is a MPOA control packet */ if ( memcmp(buff, &llc_snap_mpoa_ctrl, sizeof(llc_snap_mpoa_ctrl)) == 0 ) if ( recognize_packet(buff + sizeof(llc_snap_mpoa_ctrl)) >= 0) return 1; dprintf("mpcd: io.c check_connection(): msg from kernel\n"); msg = (struct k_message *)buff; if(msg->type == DATA_PLANE_PURGE){ send_purge_request(msg->content.eg_info.mps_ip,32, get_own_ip_addr(mpc_control.INTERFACE_NUMBER),pfd->fd); return 1; } printf("mpcd: io.c check_connection(): unknown msg %d from kernel, ignoring", msg->type); return 1; } /* * returns < 0 for unsuccessful connect, fd for ok * */ static int complete_connection(int slot) { int retval; struct sockaddr_atmsvc dummy; dprintf("mpcd: io.c: complete_connection() completing fd %d slot %d\n", fds[slot].fd, slot); /* this seems to be common method in Linux-ATM * making sure that nonblocking connect was * completed successfully */ retval = connect(fds[slot].fd,(struct sockaddr *)&dummy, sizeof(dummy)); if (retval < 0) { printf("mpcd: io.c: complete_connection(): '%s'\n", strerror(errno)); socket_type[slot] = NOT_USED; update_ingress_entry(NULL, fds[slot].fd, INGRESS_NOT_USED); close(fds[slot].fd); fds[slot].fd = -1; fds[slot].revents = 0; return 0; } socket_type[slot] &= ~CONNECTING; socket_type[slot] |= CONNECTED; fds[slot].events = POLLIN; /* We left POLLOUT accidentally in. Hope you never do the same */ fds[slot].revents = 0; if(socket_type[slot] & OUTGOING_SHORTCUT) return add_shortcut(slot, MPC_SOCKET_INGRESS); return fds[slot].fd; } /* * Called if kernel wants us to create a shortcut */ void create_ingress_svc(uint32_t ipaddr, char *atm_addr, struct atm_qos qos) { int i, new_socket; new_socket = create_shortcut(atm_addr,qos); if (new_socket < 0) { printf("mpcd: io.c: create_ingress_svc: create_shortcut failed\n"); return; } for (i = first_empty; i < OPEN_MAX; i++) { if (fds[i].fd >= 0) /* slot in use ? */ continue; fds[i].fd = new_socket; fds[i].events = POLLIN | POLLOUT; fds[i].revents = 0; break; } if (i == OPEN_MAX) { printf("mpcd: io.c: create_ingress_svc: create_shortcut: no room for new connection\n"); return; } socket_type[i] = (OUTGOING_SHORTCUT | CONNECTING); if (i >= fds_used) fds_used = i + 1; /* Store the IP address we are creating this shortcut for */ dprintf("mpcd: io.c: create_ingress_svc: adding ip 0x%x\n", ipaddr); for(i = 0; i < OPEN_MAX; i++) if (ingress_shortcuts[i].state == INGRESS_NOT_USED) break; if (i == OPEN_MAX) { printf("mpcd: io.c: create_ingress_svc: ingress no more entries\n"); return; } ingress_shortcuts[i].fd = new_socket; ingress_shortcuts[i].ipaddr = ipaddr; ingress_shortcuts[i].state = INGRESS_CONNECTING; } /* * returns < 0 for error, socket for ok * */ static int create_shortcut(char *atm_addr, struct atm_qos qos) { int s, flags, retval; struct sockaddr_atmsvc addr; dprintf("mpcd: io.c: create_shortcut() addr = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", atm_addr[0], atm_addr[1], atm_addr[2], atm_addr[3], atm_addr[4]); memset(&addr, 0, sizeof(addr)); addr.sas_family = AF_ATMSVC; memcpy(addr.sas_addr.prv, atm_addr, ATM_ESA_LEN); s = get_socket(&mpc_control.data_listen_addr); if(qos.txtp.traffic_class > ATM_UBR || qos.rxtp.traffic_class > ATM_UBR){ printf("mpcd: io.c: create_shortcut() setting qos params (cbr)\n"); if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: io.c: setsockopt SO_ATMQOS failed: %s \n",strerror(errno)); close(s); return -1; } } dprintf("mpcd: create_shortcut() got fd %d \n", s); if ( (flags = fcntl(s, F_GETFL)) < 0) { printf("mpcd: io.c: fcntl(F_GETFL) failed: %s\n", strerror(errno)); close(s); return -1; } if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { printf("mpcd: io.c: fcntl(F_SETFL) failed: %s\n", strerror(errno)); close(s); return -1; } retval = connect(s, (struct sockaddr *)&addr, sizeof(addr)); if (retval < 0 && errno != EINPROGRESS) { printf("mpcd: io.c: create_shortcut: connect failed: %s\n", strerror(errno)); return -1; } return s; } /* * Creates an active connection to MPS * * returns < 0 for error */ static int connect_to_MPS(){ int c; struct sockaddr_atmsvc mps_ctrl_addr; struct sockaddr_atmsvc ctrl_listen_addr; memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&ctrl_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memcpy(mps_ctrl_addr.sas_addr.prv,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN); memcpy(ctrl_listen_addr.sas_addr.prv,mpc_control.OWN_ATM_ADDRESS,ATM_ESA_LEN); mps_ctrl_addr.sas_family = AF_ATMSVC; ctrl_listen_addr.sas_family = AF_ATMSVC; mpc_control.MPS_socket = get_socket(&ctrl_listen_addr); if (mpc_control.MPS_socket < 0) return -1; c = connect(mpc_control.MPS_socket, (struct sockaddr *)&(mps_ctrl_addr), sizeof(struct sockaddr_atmsvc)); if( c < 0 ){ printf("mpcd: io.c: connect to MPS failed: %s \n",strerror(errno)); close(mpc_control.MPS_socket); return -1; } return 0; } --- NEW FILE: io.h --- #ifndef _MPOA_IO_H #define _MPOA_IO_H #include<atm.h> #define MAX_PACKET_LENGTH 4096 /* max size of MPOA ctrl or data packet */ void main_loop(int listen_socket); int send_to_mps(char *buff, int length); int send_to_dataplane(char *buff, int length, int fd); void keep_alive_sm(unsigned keep_alive_lifetime, int sequence_number); int get_socket(struct sockaddr_atmsvc *address); int get_listen_socket(struct sockaddr_atmsvc *address); void create_ingress_svc(uint32_t ipaddr, char *atm_addr, struct atm_qos qos); /* Socket types and states */ #define NOT_USED 0x0000 #define KERNEL 0x0001 #define OUTGOING_CTRL 0x0002 #define INCOMING_CTRL 0x0004 #define LISTENING_DATA 0x0010 #define LISTENING_CTRL 0x0020 #define OUTGOING_SHORTCUT 0x0100 #define INCOMING_SHORTCUT 0x0200 #define CONNECTING 0x1000 /* For outgoing sockets */ #define CONNECTED 0x2000 /* For outgoing sockets */ /* states for outgoing ingress shortcuts */ #define INGRESS_NOT_USED 0 #define INGRESS_REQUEST_SEND 400 #define INGRESS_CONNECTING 401 #define INGRESS_CONNECTED 402 #endif /* _MPOA_IO_H */ --- NEW FILE: CHANGELOG --- Changes from version 0.55 ========================= o mpoa_proc.c: CDV is no more requred for CBR entries o mpc.c: two small skb_buff leaks fixed o kernel: number of debug messages reduced o k_interf.c: mpcd could not be killed if MPS's address was not known Changes from version 0.52 ========================= o mpoa_proc.c: when setting QoS values for shortcuts, receive values can now be specified with just "... rx=tx" Changes from version 0.50 ========================= o lecs.c: new file. mpcd can now ask LECS for configuration info if it is given correct command line arguments o p_recogn.c: added more sanity checks for incoming packets, fixed possible dereferences of uninitialized variables o p_recogn.c: receiving MPOA Triggers now works o k_interf.c: added missing ntohl() o mpc.c: If MPS does not advertise its MAC address with MPOA Device Discover we take it from LE_ARP packet. This should remove the need for -m commandline option. o both kernel & daemon: killing mpcd with SIGHUP now makes it restart itself closing all connections and flushing both ingress and egress cache o mpcd.8: updated, example added o README.mpoa: updated Changes from version 0.46 ========================= o io.c: fixed a misuse of a buffer in set_mps_ctrl_addr() o p_recogn: If service category extension present in MPOA resolution reply, appropriate information is included in to message to kernel. New func service_category_to_traff_class(). o poll2select.[ch]: new files to circumvent bugs in poll() o io.c: poll2select() is now used instead of poll() o k_interf.c: mpcd now does nothing before MPS's atm addr is known o README.mpoa: CBR example updated and changed o mpc.c: res_reply_rcvd(): a check that CBR is supported by the other end before attempting to create a CBR shortcut was added. o mpc.c: res_reply_rcvd(): pcr-value of egress shortcut in tx-direction is checked before using the same svc as an ingress shortcut. o mpc.c: if MPS's ATM address is known to kernel when mpcd comes up, kernel sends it to mpcd. Old version waited for the next LE_ARP o mpc.c: when adding a QoS entry for a shortcut the old entry is overwritten instead. Old version just added another IP o mpoa_proc.c: CBR QoS now only wants max_pcr, max_cdv, and max_sdu values Changes from version 0.43 ============================== o io.c: poll() seems to have problems returning correct values fixed it with a workaround o mpcd: put all the global variables in one global struct o io.c: listen sockets are now created with ATM_ANYCLASS traffic class o p_recogn.c: calculation of ip-address mask from a prefix-length in a CIE o io.c: mpoad no more exits when something really bad happens to it's sockets. Instead it does a soft boot and tries again o mpc.c: now correct pointer is kfree()ed in atm_mpoa_delete_qos() o mpc.c: while purging ingress entries ip-masks are taken into consideration o mpoa_caches.[ch]: new function in_cache_search_with_mask() o mpc.h: struct mpoa_client contains a new struct mpc_parameters o mpc.c: lane_assoc_ind() handles also MPC configuration TLVs o mpc.c: mpc->number_of_mps_macs is now updated correctly Changes from version pre0.43-0 ============================== o p_recogn.c: fixed a bug in extension parsing o io.c: fixed handling of the pollfd array indexing o p_recogn.c: chechksum checking for incoming control packets o main.c: default values for local listen ATM-adresses o getvars.[ch]: removed stupid set_own_atm_address function --- NEW FILE: Makefile.am --- sbin_PROGRAMS = mpcd LDADD = $(top_builddir)/src/lib/libatm.la mpcd_SOURCES = get_vars.c get_vars.h io.c io.h k_interf.c k_interf.h main.c \ p_factory.c p_recogn.c id_list.c tag_list.c \ poll2select.c poll2select.h lecs.c lecs.h packets.h man_MANS = mpcd.8 EXTRA_DIST = $(man_MANS) CHANGELOG README.mpoa TODO --- NEW FILE: k_interf.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/param.h> /* for OPEN_MAX */ #include <stdint.h> #include <netinet/in.h> /* for ntohl() */ #include <linux/atmmpc.h> #include <atm.h> #include "k_interf.h" #include "packets.h" #include "io.h" #include "get_vars.h" #if 0 #define dprintf printf #else #define dprintf(format,args...) #endif extern int keep_alive_sm_running; /* from io.c */ extern struct mpc_control mpc_control; /* from main.c */ static void snd_mpoa_res_rqst(struct k_message *msg); static void snd_mpoa_res_rtry(struct k_message *msg); static void set_mps_ctrl_addr(struct k_message *msg); static void stop_keep_alive_sm(void); static uint32_t traff_class_to_service_category(uint8_t traffic_class); /* * returns < 0 for error * */ int send_to_kernel(struct k_message *msg) { if (write(mpc_control.kernel_socket, msg, sizeof(struct k_message)) != sizeof(struct k_message) ) { printf("mpcd: k_interf.c: write to kernel failed!\n"); return -1; } return 1; } /* * returns 0 for error * */ int msg_from_kernel(int fd) { ssize_t bytes_read; struct k_message msg; memset(&msg,0,sizeof(struct k_message)); bytes_read = read(fd, (void *)&msg, sizeof(msg)); if (bytes_read < 0) { printf("mpcd: k_interf.c: read failed from kernel: %s\n", strerror(errno)); return 0; } if (bytes_read == 0) { printf("mpcd: k_interf.c:EOF from kernel\n"); return 0; } if (bytes_read != sizeof(msg)) { printf("mpcd: k_interf.c: msg from kernel wrong size\n"); return 0; } dprintf("mpcd: k_interf.c: message from kernel: "); if (msg.type == DIE) { dprintf(" die\n"); exit(0); } /* do nothing if MPS's control ATM address is not known */ if (msg.type != SET_MPS_CTRL_ADDR && !mpc_control.mps_ctrl_addr_set) return 0; switch(msg.type) { case SND_MPOA_RES_RQST: dprintf("snd_mpoa_res_rqst.\n"); snd_mpoa_res_rqst(&msg); return 1; break; /* not reached */ case SND_MPOA_RES_RTRY: dprintf("snd_mpoa_res_rtry.\n"); snd_mpoa_res_rtry(&msg); return 1; break; /* not reached */ case SET_MPS_CTRL_ADDR: dprintf("set_mps_ctrl_addr.\n"); set_mps_ctrl_addr(&msg); return 1; break; /* not reached */ case STOP_KEEP_ALIVE_SM: dprintf("stop_keep_alive_sm.\n"); stop_keep_alive_sm(); return 1; break; /* not reached */ case EGRESS_ENTRY_REMOVED: dprintf("egress_entry_removed.\n"); remove_tag(msg.content.eg_info.tag); return 1; break; /* not reached */ case SND_EGRESS_PURGE: dprintf("snd_egress_purge,cache_id = %u.\n",msg.content.eg_info.cache_id); send_egress_cache_purge_request(0, /* 1 == no reply, 0 == reply requested */ ntohl(msg.content.eg_info.mps_ip), 32, get_own_ip_addr(mpc_control.INTERFACE_NUMBER), msg.content.eg_info.cache_id); return 1; break; case OPEN_INGRESS_SVC: dprintf(" open_ingress_svc\n"); create_ingress_svc(msg.content.in_info.in_dst_ip, msg.content.in_info.eg_MPC_ATM_addr, msg.qos); return 1; break; case RELOAD: printf(" reload\n"); return 0; break; default: dprintf("unknown message %d\n", msg.type); return 0; break; /* not reached */ } return 0; /* not reached */ } static void snd_mpoa_res_rqst(struct k_message *msg){ send_resolution_request(0, 1, /* Source ip present */ msg->content.in_info.in_dst_ip, 0, /* prefix length */ traff_class_to_service_category(msg->qos.txtp.traffic_class)); return; } static void snd_mpoa_res_rtry(struct k_message *msg){ uint32_t rqst_id = search_by_type(MPOA_RESOLUTION_REQUEST, msg->content.in_info.in_dst_ip); send_resolution_request(rqst_id, 1, msg->content.in_info.in_dst_ip, 0, traff_class_to_service_category(msg->qos.txtp.traffic_class)); return; } static void set_mps_ctrl_addr(struct k_message *msg) { char buffer[ATM_ESA_LEN]; int i; struct sockaddr_atmsvc mps_ctrl_addr; char *buff = buffer; memcpy(mps_ctrl_addr.sas_addr.prv, msg->MPS_ctrl, ATM_ESA_LEN); mps_ctrl_addr.sas_family = AF_ATMSVC; if(mpc_control.mps_ctrl_addr_set && !memcmp(msg->MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)) return; if(mpc_control.mps_ctrl_addr_set && memcmp(msg->MPS_ctrl,mpc_control.MPS_CTRL_ATM_ADDR,ATM_ESA_LEN)){ printf("mpcd: k_interf.c: new MPS "); for (i = 0; i < ATM_ESA_LEN; i++) printf("%02x", msg->MPS_ctrl[i]); printf("\n"); return; } memcpy(mpc_control.MPS_CTRL_ATM_ADDR, msg->MPS_ctrl, ATM_ESA_LEN); printf("mpcd: k_interf.c: setting MPS control ATM address to "); if(atm2text(buff,ATM_ESA_LEN, (struct sockaddr*)&mps_ctrl_addr, T2A_SVC)<0) { for (i = 0; i < ATM_ESA_LEN; i++) printf("%02x", mpc_control.MPS_CTRL_ATM_ADDR[i]); printf("\n"); } else printf("%s\n", buff); mpc_control.mps_ctrl_addr_set = 1; return; } static void stop_keep_alive_sm(){ keep_alive_sm_running = 0; return; } /* * Converts linux-ATM traffic descriptions to those used in MPOA ATM service * category extension. Only UBR and CBR supported. */ static uint32_t traff_class_to_service_category(uint8_t traffic_class){ switch(traffic_class){ case ATM_NONE: return 0; break; case ATM_UBR: return 0; break; case ATM_CBR: return CBR; break; default: return 0; } } --- NEW FILE: k_interf.h --- #ifndef K_INTERF_H #define K_INTERF_H int send_to_kernel( struct k_message *msg); int msg_from_kernel(int fd); #endif /* K_INTERF_H */ --- NEW FILE: get_vars.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <stdint.h> #include <atm.h> #include <linux/atmdev.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netdb.h> #include <unistd.h> #include <net/if.h> #include <arpa/inet.h> #include <errno.h> #include "packets.h" #include "get_vars.h" #include "io.h" extern struct mpc_control mpc_control; /* From main.c */ /* Returns the Time To Live value. */ int get_ttl(){ int optvalue = 1; unsigned optlength = sizeof(optvalue); int sockfd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); getsockopt( sockfd, IPPROTO_IP, IP_TTL, &optvalue, &optlength ); close(sockfd); return optvalue; } /* * Returns clients own IP-address. According to interface number. * */ uint32_t get_own_ip_addr(int iface_nmbr ){ struct ifreq req; int fd; char * addr; uint32_t address; char name[6]; sprintf(name, "lec%d", iface_nmbr ); memcpy(req.ifr_ifrn.ifrn_name,name,sizeof(name)); fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP ); if(fd < 0){ printf("mpcd: get_vars.c: socket creation failed.\n"); exit(1); } if(ioctl(fd,SIOCGIFADDR,&req)<0){ printf("mpcd: get_vars.c: ioctl failed: %s\n", strerror(errno)); exit(1); } addr = req.ifr_ifru.ifru_addr.sa_data; address = ((unsigned char)addr[2] << 24) | ((unsigned char)addr[3] << 16) | ((unsigned char)addr[4] << 8 ) | (unsigned char)addr[5] ; close(fd); return address; } int get_own_atm_addr(unsigned char * address){ memcpy(address,mpc_control.data_listen_addr.sas_addr.prv,ATM_ESA_LEN); return 1; } --- NEW FILE: get_vars.h --- #ifndef GET_VARS_H #define GET_VARS_H #include <linux/types.h> int get_ttl(void); uint32_t get_own_ip_addr(int iface_nmbr); int get_own_atm_addr(unsigned char *address ); #endif /* GET_VARS_H */ --- NEW FILE: lecs.c --- /* lecs.c, get MPOA configuration info from LECS */ #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <string.h> #include <netinet/in.h> /* htons() and friends */ #include <unistd.h> #include <errno.h> #include <atm.h> #include <atmsap.h> #include <linux/atmmpc.h> /* for MPOA Device type TLV */ #include "lecs.h" #include "k_interf.h" #define MAXFRAME 1024 static int get_lecs_socket(struct sockaddr_atmsvc *sa); static int send_request(int fd, char *buff, char *lec_addr, char *elan_name); static int get_reply(int fd, char *buff, struct mpc_parameters *params); void get_mpc_config(struct sockaddr_atmsvc *sa, char *lec_addr, char *elan_name) { int s; char buff[MAXFRAME]; struct k_message msg; s = get_lecs_socket(sa); if (s < 0) return; memset(buff, 0, sizeof(buff)); if (send_request(s, buff, lec_addr, elan_name) < 0) { printf("mpcd: lecs.c: send_request failed, using defaults\n"); return; } msg.content.params.mpc_p1 = MPC_P1; msg.content.params.mpc_p2 = MPC_P2; msg.content.params.mpc_p4 = MPC_P4; msg.content.params.mpc_p5 = MPC_P5; msg.content.params.mpc_p6 = MPC_P6; if (get_reply(s, buff, &msg.content.params) < 0) { printf("mpcd: lecs.c: get_config failed, using defaults\n"); return; } msg.type = SET_MPC_PARAMS; send_to_kernel(&msg); printf("mpcd: lecs.c: get_config: about to return\n"); return; } static int send_request(int fd, char *buff, char *lec_addr, char *elan_name) { char *tmp; int retval; struct le_config_frame *frame; frame = (struct le_config_frame *)buff; frame->marker = htons(0xff00); frame->protocol = 0x01; frame->version = 0x01; frame->opcode = htons(0x0001); frame->tran_id = htonl(42); frame->flags = htons(0x002); memcpy(frame->src_atm_addr, lec_addr, ATM_ESA_LEN); frame->num_tlvs = 1; if (elan_name != NULL) { strcpy(frame->elan_name, elan_name); frame->elan_name_size = strlen(elan_name); } /* add the MPOA device type TLV */ tmp = buff + sizeof(struct le_config_frame); *(uint32_t *)tmp = htonl(TLV_MPOA_DEVICE_TYPE); tmp += 4; *tmp++ = 22; /* device type field + MPC's ATM address */ *tmp++ = MPC; *tmp++ = 0; memcpy(tmp, lec_addr, ATM_ESA_LEN); tmp += ATM_ESA_LEN; retval = write(fd, buff, tmp - buff); if (retval < 0 || retval != (tmp - buff)) return -1; return 0; } static int get_reply(int fd, char *buff, struct mpc_parameters *params) { int retval; uint32_t type; uint8_t length, *tlvs, *end_of_tlvs; struct le_config_frame *frame; retval = read(fd, buff, MAXFRAME); if (retval < 0) return -1; frame = (struct le_config_frame *)buff; if (frame->status != 0) { printf("mpcd: lecs.c: get_reply: config status %d\n", frame->status); return -1; } if (frame->num_tlvs == 0) { printf("mpcd: lecs.c: get_reply: no TLVS\n"); return -1; } tlvs = buff + sizeof(struct le_config_frame); end_of_tlvs = buff + retval; while (end_of_tlvs - tlvs >= 5 && frame->num_tlvs-- > 0) { type = (tlvs[0] << 24) | (tlvs[1] << 16) | (tlvs[2] << 8) | tlvs[3]; length = tlvs[4]; tlvs += 5; /* Sampo-Add: start */ switch(type){ case TLV_SC_SETUP_FRAME_COUNT: params->mpc_p1 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p1 = htons(params->mpc_p1); printf("mpcd: lecs.c: get_reply: MPC_p1 = %d\n",params->mpc_p1); break; case TLV_SC_SETUP_FRAME_TIME: params->mpc_p2 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p2 = htons(params->mpc_p2); printf("mpcd: lecs.c: get_reply: MPC_p2 = %d\n",params->mpc_p2); break; case TLV_FLOW_DETECTION_PROTOCOLS: memcpy(params->mpc_p3, tlvs, length); printf("mpcd: lecs.c: get_reply: MPC_p3 = %s\n",params->mpc_p3); break; case TLV_MPC_ININTIAL_RETRY_TIME: params->mpc_p4 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p4 = htons(params->mpc_p4); printf("mpcd: lecs.c: get_reply: MPC_p4 = %d\n",params->mpc_p4); break; case TLV_MPC_RETRY_TIME_MAXIMUM: params->mpc_p5 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p5 = htons(params->mpc_p5); printf("mpcd: lecs.c: get_reply: MPC_p5 = %d\n",params->mpc_p5); break; case TLV_HOLD_DOWN_TIME: params->mpc_p6 = (*(tlvs+1)<<8) | (*tlvs); params->mpc_p6 = htons(params->mpc_p6); printf("mpcd: lecs.c: get_reply: MPC_p6 = %d\n",params->mpc_p6); break; default: printf("mpcd: lecs.c: get_reply: TLV type 0x%x\n", type); break; } tlvs += length; /* Sampo-Add: end */ } if (end_of_tlvs - tlvs != 0) printf("mpcd: lecs.c: get_reply: ignoring %d bytes of trailing TLV carbage\n", end_of_tlvs - tlvs); return 1; } static int get_lecs_socket(struct sockaddr_atmsvc *sa) { int s, retval; struct atm_qos qos; struct atm_sap sap; s = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (s < 0){ printf("mpcd: lecs.c: socket failed: %s\n", strerror(errno)); return -1; } memset(&qos, 0, sizeof(qos)); memset(&sap, 0, sizeof(sap)); qos.aal = ATM_AAL5; qos.txtp.traffic_class = ATM_UBR; qos.rxtp.traffic_class = ATM_UBR; qos.txtp.max_sdu = 1516; qos.rxtp.max_sdu = 1516; if (setsockopt(s, SOL_ATM,SO_ATMQOS, &qos, sizeof(qos)) < 0){ printf("mpcd: lecs.c: setsockopt SO_ATMQOS failed: %s\n", strerror(errno)); close(s); return -1; } sap.blli[0].l2_proto = ATM_L2_NONE; sap.blli[0].l3_proto = ATM_L3_TR9577; sap.blli[0].l3.tr9577.ipi = NLPID_IEEE802_1_SNAP; sap.blli[0].l3.tr9577.snap[0] = 0x00; sap.blli[0].l3.tr9577.snap[1] = 0xa0; sap.blli[0].l3.tr9577.snap[2] = 0x3e; sap.blli[0].l3.tr9577.snap[3] = 0x00; sap.blli[0].l3.tr9577.snap[4] = 0x01; if (setsockopt(s, SOL_ATM,SO_ATMSAP, &sap, sizeof(sap)) < 0) { printf("mpcd: lecs.c: setsockop SO_ATMSAP failed: %s\n", strerror(errno)); close (s); return -1; } retval = connect(s, (struct sockaddr *)sa, sizeof(struct sockaddr_atmsvc)); if (retval < 0) { printf("mpcd: lecs.c: connect failed: %s\n", strerror(errno)); close (s); return -1; } return s; } --- NEW FILE: lecs.h --- #ifndef LECS_H #define LECS_H void get_mpc_config(struct sockaddr_atmsvc *sa, char *lec_addr, char *elan_name); struct le_config_frame { uint16_t marker; uint8_t protocol; uint8_t version; uint16_t opcode; uint16_t status; uint32_t tran_id; uint16_t lecid; uint16_t flags; uint8_t src_lan[8]; uint8_t target_lan[8]; uint8_t src_atm_addr[ATM_ESA_LEN]; uint8_t lan_type; uint8_t max_frame_size; uint8_t num_tlvs; uint8_t elan_name_size; uint8_t target_atm_addr[ATM_ESA_LEN]; uint8_t elan_name[32]; /* TLVs if any */ } __attribute__ ((packed)); /* MPOA Configuration TLVs */ #define TLV_SC_SETUP_FRAME_COUNT 0x00a03e24 /* MPC_p1 */ #define TLV_SC_SETUP_FRAME_TIME 0x00a03e25 /* MPC_p2 */ #define TLV_FLOW_DETECTION_PROTOCOLS 0x00a03e26 /* MPC_p3 */ #define TLV_MPC_ININTIAL_RETRY_TIME 0x00a03e27 /* MPC_p4 */ #define TLV_MPC_RETRY_TIME_MAXIMUM 0x00a03e28 /* MPC_p5 */ #define TLV_HOLD_DOWN_TIME 0x00a03e29 /* MPC_p6 */ #endif /* LECS_H */ --- NEW FILE: main.c --- #if HAVE_CONFIG_H #include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <sys/utsname.h> #include <getopt.h> #include <time.h> #include <sys/ioctl.h> #include <atm.h> #include <linux/atmdev.h> #include <linux/atmmpc.h> #include <sys/socket.h> #include <sys/time.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <atm.h> #include <linux/if_ether.h> #include <signal.h> #include "packets.h" #include "io.h" #include "k_interf.h" #include "get_vars.h" #include "lecs.h" /* * Global struct containing sockets addresses and parameters. */ struct mpc_control mpc_control; static void create_kernel_socket(int itf); static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ); static int set_mps_mac_addr(void); static void usage(const char *progname); static void signal_handler(int sig){ struct k_message msg; memset(&msg,0,sizeof(struct k_message)); if (sig == SIGHUP) msg.type = RELOAD; else msg.type = CLEAN_UP_AND_EXIT; send_to_kernel(&msg); printf("mpcd: main.c: signal_handler() signal %d\n", sig); return; } /* * Initialize our listen addresses for * the incoming/outgoing MPOA connections */ static void init_default_addresses(struct sockaddr_atmsvc *ctrl, struct sockaddr_atmsvc *data) { struct sockaddr_atmsvc sa; struct atmif_sioc req; int fd; unsigned char wellknown_lecs[ATM_ESA_LEN]; memset(wellknown_lecs,0,ATM_ESA_LEN); wellknown_lecs[0] = 0x47; wellknown_lecs[2] = 0x79; wellknown_lecs[14] = 0xa0; wellknown_lecs[15] = 0x3e; wellknown_lecs[18] = 0x01; fd = get_socket(NULL); req.number=0; req.arg=&sa; req.length=sizeof(struct sockaddr_atmsvc); if ( ioctl(fd, ATM_GETADDR, &req) <0 ){ perror("mpcd: main.c: ioctl(ATM_GETADDR)"); exit(-1); } ctrl->sas_family = AF_ATMSVC; data->sas_family = AF_ATMSVC; mpc_control.lecs_address.sas_family = AF_ATMSVC; /* ATM address for the incoming/outgoing MPOA control connections */ sa.sas_addr.prv[ATM_ESA_LEN-1] = 50; memcpy(ctrl->sas_addr.prv, sa.sas_addr.prv, ATM_ESA_LEN); memcpy(mpc_control.OWN_ATM_ADDRESS, ctrl->sas_addr.prv, ATM_ESA_LEN); memcpy(mpc_control.lecs_address.sas_addr.prv,wellknown_lecs, ATM_ESA_LEN); /* ATM address for the incoming/outgoing MPOA shortcuts */ sa.sas_addr.prv[ATM_ESA_LEN-1] = 51; memcpy(data->sas_addr.prv, sa.sas_addr.prv, ATM_ESA_LEN); close(fd); return; } int main(int argc, char **argv){ int listen_socket; int opt_ret = 0; struct k_message msg; struct sockaddr_atmsvc control_listen_addr; struct sockaddr_atmsvc mps_ctrl_addr; struct sockaddr_atmsvc lec_addr; memset(&control_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&mpc_control.data_listen_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&lec_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&mps_ctrl_addr,0,sizeof(struct sockaddr_atmsvc)); memset(&msg,0,sizeof(struct k_message)); memset(&mpc_control,0,sizeof(mpc_control)); mpc_control.elan_name[32] = '\0'; init_default_addresses(&control_listen_addr, &mpc_control.data_listen_addr); while( opt_ret != -1 ){ opt_ret = getopt(argc, argv, "h:s:l:c:L:n:C:i:m:"); switch(opt_ret) { case 'h': usage(argv[0]); exit(0); break; case 's': if(text2atm(optarg,(struct sockaddr *)&control_listen_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.OWN_ATM_ADDRESS,control_listen_addr.sas_addr.prv, ATM_ESA_LEN); break; case 'l': if(text2atm(optarg,(struct sockaddr *)&mpc_control.data_listen_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } break; case 'c': if(text2atm(optarg,(struct sockaddr *)&mps_ctrl_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.MPS_CTRL_ATM_ADDR,mps_ctrl_addr.sas_addr.prv,ATM_ESA_LEN); mpc_control.mps_ctrl_addr_set = 1; break; case 'L': if(text2atm(optarg,(struct sockaddr *)&lec_addr, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } memcpy(mpc_control.LEC_ADDRESS,lec_addr.sas_addr.prv,ATM_ESA_LEN); mpc_control.use_lecs = 1; break; case 'n': strncpy(mpc_control.elan_name,optarg,33); break; case 'C': if(text2atm(optarg,(struct sockaddr *)&mpc_control.lecs_address, sizeof(struct sockaddr_atmsvc),T2A_SVC | T2A_NAME)<0){ printf("mpcd: main.c: text2atm failed.\n"); usage(argv[0]); exit(1); } break; case 'm': strncpy(mpc_control.MPS_MAC_ADDRESS,optarg,13); mpc_control.mps_mac_addr_set = 1; break; case 'i': mpc_control.INTERFACE_NUMBER = atoi(optarg); break; } } if (argc != optind) { usage(argv[0]); exit(1); } while(1){ create_kernel_socket(mpc_control.INTERFACE_NUMBER); if(mpc_control.use_lecs){ get_mpc_config(&mpc_control.lecs_address, mpc_control.LEC_ADDRESS, mpc_control.elan_name); } msg.type = SET_MPC_CTRL_ADDR; memcpy(msg.MPS_ctrl,mpc_control.OWN_ATM_ADDRESS,ATM_ESA_LEN); if (send_to_kernel(&msg) < 0) { printf("mpcd: main.c: send_to_kernel(SET_MPC_CTRL_ADDR) failed\n"); exit(1); } if(mpc_control.mps_mac_addr_set) set_mps_mac_addr(); listen_to_MPS( control_listen_addr ); if ( (listen_socket = get_listen_socket(&mpc_control.data_listen_addr)) < 0) { printf("mpcd: main.c: listen_socket creation failed\n"); exit (1); } signal(SIGHUP, signal_handler); signal(SIGINT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGABRT, signal_handler); signal(SIGTERM, signal_handler); main_loop(listen_socket); sleep(5); printf("mpcd: main.c: going back to main loop...\n"); } return 0; } static void create_kernel_socket(int itf) { mpc_control.kernel_socket = socket(PF_ATMSVC, SOCK_DGRAM, 0); if (mpc_control.kernel_socket < 0) { printf("mpcd: main.c: kernel socket creation failed: %s\n", strerror(errno)); exit (1); } if ( ioctl(mpc_control.kernel_socket, ATMMPC_CTRL, itf) < 0) { printf("mpcd: main.c: kernel socket ioctl(ATMMPC_CTRL) failed: %s\n", strerror(errno)); exit (1); } return; } static int listen_to_MPS( struct sockaddr_atmsvc ctrl_listen_addr ){ /* soketti, joka kuuntelee MPC:n Control ATM-osoitteessa */ mpc_control.MPS_listen_socket = get_listen_socket(&ctrl_listen_addr); if (mpc_control.MPS_listen_socket < 0) return -1; return 0; } static int set_mps_mac_addr(){ char *string = mpc_control.MPS_MAC_ADDRESS; struct k_message msg; unsigned char mac_addr[ETH_ALEN]; int tmp; int i = strlen(string); memset(&msg,0,sizeof(struct k_message)); if (i != 12){ printf("mpcd: main.c: incorrect mac address.\n"); exit(1); } for(i=0;i<6;i++) { sscanf(&string[i*2],"%2x",&tmp); mac_addr[i]=(unsigned char)tmp; } msg.type = SET_MPS_MAC_ADDR; memcpy(&msg.MPS_ctrl,&mac_addr,ETH_ALEN); send_to_kernel(&msg); return 0; } static void usage( const char * progname ){ printf("Usage: %s [-s our_control_listen_ATM_Address] [-l our_data_listen_address]\n" " [-c MPS_control_ATM_Address] [-i interface_number]\n" " [-m MPS_MAC_address]\n" " [-L lec_address [-n elan_name [-C lecs_address]]]\n", progname); return; } --- NEW FILE: mpcd.8 --- .TH mpcd 8 "Nov 17, 1998" "Linux" "Maintenance Commands" .SH NAME mpcd \- ATM MPOA (Multi\-Protocol Over ATM) client daemon .SH SYNOPSIS .B mpcd .B [ -s .I Control ATM address .B ] .B [ -l .I Data ATM address .B ] .B [ -c .I MPS control ATM address .B ] .B [ -i .I Interface number .B ] .B [ -m .I MPS MAC address .B ] .B [ -L .I LEC address .B [ -n .I ELAN name .B ] .B [ -C .I LECS Address .B ]] .SH DESCRIPTION MPOA client .SM(MPC) is responsible for creating and receiving internetwork layer shortcuts. Using these shortcuts MPCs forward unicast internetwork layer packets effectively over ATM without need for routing protocols. .PP .SM MPC has two roles; ingress and egress. In ingress role .SM MPC detects flows destined outside it's own subnet and tries to establish shortcuts to those destinations. In egress role .SM MPC accepts shortcuts and packets arriving on those shortcuts. Maintaining shortcuts is done with the help of .SM MPOA server .SM(MPS). .PP Just as the Linux .SM LAN Emulation client, .SM MPOA client is also divided in two parts. The parts are kernel component and a daemon process. The daemon opens and receives data shortcuts and control connections with the kernel component. The kernel component tallies packets flowing out from the .SM LANE device and makes the decision if a packet should be forwarded using .SM LANE or .SM MPOA shortcuts. .PP If the daemon is killed with .B SIGHUP it will close all the open connections, purge ingress and egress cache entries, query .SM LECS if applicable and then restart itself. .PP Linux MPOA client only supports non-LLC-muxed shortcuts. The number of supported MPOA clients is unlimited. .SH OPTIONS .IP "-s Control ATM address" Local ATM address this MPC uses for MPOA control connections. .IP "-l Data ATM address" Local ATM address from and to which MPOA shortcuts are established. .IP "-c MPS control ATM address" ATM address of MPS. Only needed if MPS can not advertise it by itself. .IP "-i Interface number" The interface number of LEC this MPC serves. E.g. 2 for "lec2". .IP "-m MPS MAC address" MAC address of default router where MPS recides. Only useful if the MPOA server fails to advertise itself. .IP "-L LEC address" Listen address of the .SM LANE client zeppelin. mpcd uses this address as its own .SM ATM address when it queries .SM LECS for .SM MPC configuration parameters. If this option is not present then mpcd .B will not use .SM LECS to query for configuration parameters. This option is normally the same as zeppelin's -l option. .IP "-n ELAN name" Name of the .SM ELAN for which mpcd asks for parameters when it connects to .SM LECS. If this option is not given, .SM LECS should respond with parameters belonging to the default .SM ELAN if one exists. This option is normally the same as zeppelin's -n option. .IP "-C LECS address" ATM address of .SM LECS mpcd asks for parameters. If this option is left empty and -L is g... [truncated message content] |