162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <stdio.h> 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci#include <unistd.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <fcntl.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <termios.h> 1362306a36Sopenharmony_ci#include <sys/wait.h> 1462306a36Sopenharmony_ci#include <net_user.h> 1562306a36Sopenharmony_ci#include <os.h> 1662306a36Sopenharmony_ci#include "slip.h" 1762306a36Sopenharmony_ci#include <um_malloc.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int slip_user_init(void *data, void *dev) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct slip_data *pri = data; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci pri->dev = dev; 2462306a36Sopenharmony_ci return 0; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int set_up_tty(int fd) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci int i; 3062306a36Sopenharmony_ci struct termios tios; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (tcgetattr(fd, &tios) < 0) { 3362306a36Sopenharmony_ci printk(UM_KERN_ERR "could not get initial terminal " 3462306a36Sopenharmony_ci "attributes\n"); 3562306a36Sopenharmony_ci return -1; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci tios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; 3962306a36Sopenharmony_ci tios.c_iflag = IGNBRK | IGNPAR; 4062306a36Sopenharmony_ci tios.c_oflag = 0; 4162306a36Sopenharmony_ci tios.c_lflag = 0; 4262306a36Sopenharmony_ci for (i = 0; i < NCCS; i++) 4362306a36Sopenharmony_ci tios.c_cc[i] = 0; 4462306a36Sopenharmony_ci tios.c_cc[VMIN] = 1; 4562306a36Sopenharmony_ci tios.c_cc[VTIME] = 0; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci cfsetospeed(&tios, B38400); 4862306a36Sopenharmony_ci cfsetispeed(&tios, B38400); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { 5162306a36Sopenharmony_ci printk(UM_KERN_ERR "failed to set terminal attributes\n"); 5262306a36Sopenharmony_ci return -1; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct slip_pre_exec_data { 5862306a36Sopenharmony_ci int stdin_fd; 5962306a36Sopenharmony_ci int stdout_fd; 6062306a36Sopenharmony_ci int close_me; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void slip_pre_exec(void *arg) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct slip_pre_exec_data *data = arg; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (data->stdin_fd >= 0) 6862306a36Sopenharmony_ci dup2(data->stdin_fd, 0); 6962306a36Sopenharmony_ci dup2(data->stdout_fd, 1); 7062306a36Sopenharmony_ci if (data->close_me >= 0) 7162306a36Sopenharmony_ci close(data->close_me); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int slip_tramp(char **argv, int fd) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct slip_pre_exec_data pe_data; 7762306a36Sopenharmony_ci char *output; 7862306a36Sopenharmony_ci int pid, fds[2], err, output_len; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci err = os_pipe(fds, 1, 0); 8162306a36Sopenharmony_ci if (err < 0) { 8262306a36Sopenharmony_ci printk(UM_KERN_ERR "slip_tramp : pipe failed, err = %d\n", 8362306a36Sopenharmony_ci -err); 8462306a36Sopenharmony_ci goto out; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci err = 0; 8862306a36Sopenharmony_ci pe_data.stdin_fd = fd; 8962306a36Sopenharmony_ci pe_data.stdout_fd = fds[1]; 9062306a36Sopenharmony_ci pe_data.close_me = fds[0]; 9162306a36Sopenharmony_ci err = run_helper(slip_pre_exec, &pe_data, argv); 9262306a36Sopenharmony_ci if (err < 0) 9362306a36Sopenharmony_ci goto out_close; 9462306a36Sopenharmony_ci pid = err; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci output_len = UM_KERN_PAGE_SIZE; 9762306a36Sopenharmony_ci output = uml_kmalloc(output_len, UM_GFP_KERNEL); 9862306a36Sopenharmony_ci if (output == NULL) { 9962306a36Sopenharmony_ci printk(UM_KERN_ERR "slip_tramp : failed to allocate output " 10062306a36Sopenharmony_ci "buffer\n"); 10162306a36Sopenharmony_ci os_kill_process(pid, 1); 10262306a36Sopenharmony_ci err = -ENOMEM; 10362306a36Sopenharmony_ci goto out_close; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci close(fds[1]); 10762306a36Sopenharmony_ci read_output(fds[0], output, output_len); 10862306a36Sopenharmony_ci printk("%s", output); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci err = helper_wait(pid); 11162306a36Sopenharmony_ci close(fds[0]); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci kfree(output); 11462306a36Sopenharmony_ci return err; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciout_close: 11762306a36Sopenharmony_ci close(fds[0]); 11862306a36Sopenharmony_ci close(fds[1]); 11962306a36Sopenharmony_ciout: 12062306a36Sopenharmony_ci return err; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int slip_open(void *data) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct slip_data *pri = data; 12662306a36Sopenharmony_ci char version_buf[sizeof("nnnnn\0")]; 12762306a36Sopenharmony_ci char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; 12862306a36Sopenharmony_ci char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 12962306a36Sopenharmony_ci NULL }; 13062306a36Sopenharmony_ci int sfd, mfd, err; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci err = get_pty(); 13362306a36Sopenharmony_ci if (err < 0) { 13462306a36Sopenharmony_ci printk(UM_KERN_ERR "slip-open : Failed to open pty, err = %d\n", 13562306a36Sopenharmony_ci -err); 13662306a36Sopenharmony_ci goto out; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci mfd = err; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err = open(ptsname(mfd), O_RDWR, 0); 14162306a36Sopenharmony_ci if (err < 0) { 14262306a36Sopenharmony_ci printk(UM_KERN_ERR "Couldn't open tty for slip line, " 14362306a36Sopenharmony_ci "err = %d\n", -err); 14462306a36Sopenharmony_ci goto out_close; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci sfd = err; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci err = set_up_tty(sfd); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci goto out_close2; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci pri->slave = sfd; 15362306a36Sopenharmony_ci pri->slip.pos = 0; 15462306a36Sopenharmony_ci pri->slip.esc = 0; 15562306a36Sopenharmony_ci if (pri->gate_addr != NULL) { 15662306a36Sopenharmony_ci sprintf(version_buf, "%d", UML_NET_VERSION); 15762306a36Sopenharmony_ci strcpy(gate_buf, pri->gate_addr); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci err = slip_tramp(argv, sfd); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (err < 0) { 16262306a36Sopenharmony_ci printk(UM_KERN_ERR "slip_tramp failed - err = %d\n", 16362306a36Sopenharmony_ci -err); 16462306a36Sopenharmony_ci goto out_close2; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci err = os_get_ifname(pri->slave, pri->name); 16762306a36Sopenharmony_ci if (err < 0) { 16862306a36Sopenharmony_ci printk(UM_KERN_ERR "get_ifname failed, err = %d\n", 16962306a36Sopenharmony_ci -err); 17062306a36Sopenharmony_ci goto out_close2; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci iter_addresses(pri->dev, open_addr, pri->name); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci else { 17562306a36Sopenharmony_ci err = os_set_slip(sfd); 17662306a36Sopenharmony_ci if (err < 0) { 17762306a36Sopenharmony_ci printk(UM_KERN_ERR "Failed to set slip discipline " 17862306a36Sopenharmony_ci "encapsulation - err = %d\n", -err); 17962306a36Sopenharmony_ci goto out_close2; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci return mfd; 18362306a36Sopenharmony_ciout_close2: 18462306a36Sopenharmony_ci close(sfd); 18562306a36Sopenharmony_ciout_close: 18662306a36Sopenharmony_ci close(mfd); 18762306a36Sopenharmony_ciout: 18862306a36Sopenharmony_ci return err; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void slip_close(int fd, void *data) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci struct slip_data *pri = data; 19462306a36Sopenharmony_ci char version_buf[sizeof("nnnnn\0")]; 19562306a36Sopenharmony_ci char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, 19662306a36Sopenharmony_ci NULL }; 19762306a36Sopenharmony_ci int err; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (pri->gate_addr != NULL) 20062306a36Sopenharmony_ci iter_addresses(pri->dev, close_addr, pri->name); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci sprintf(version_buf, "%d", UML_NET_VERSION); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci err = slip_tramp(argv, pri->slave); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (err != 0) 20762306a36Sopenharmony_ci printk(UM_KERN_ERR "slip_tramp failed - errno = %d\n", -err); 20862306a36Sopenharmony_ci close(fd); 20962306a36Sopenharmony_ci close(pri->slave); 21062306a36Sopenharmony_ci pri->slave = -1; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ciint slip_user_read(int fd, void *buf, int len, struct slip_data *pri) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci return slip_proto_read(fd, buf, len, &pri->slip); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint slip_user_write(int fd, void *buf, int len, struct slip_data *pri) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return slip_proto_write(fd, buf, len, &pri->slip); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void slip_add_addr(unsigned char *addr, unsigned char *netmask, 22462306a36Sopenharmony_ci void *data) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct slip_data *pri = data; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (pri->slave < 0) 22962306a36Sopenharmony_ci return; 23062306a36Sopenharmony_ci open_addr(addr, netmask, pri->name); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void slip_del_addr(unsigned char *addr, unsigned char *netmask, 23462306a36Sopenharmony_ci void *data) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct slip_data *pri = data; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (pri->slave < 0) 23962306a36Sopenharmony_ci return; 24062306a36Sopenharmony_ci close_addr(addr, netmask, pri->name); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciconst struct net_user_info slip_user_info = { 24462306a36Sopenharmony_ci .init = slip_user_init, 24562306a36Sopenharmony_ci .open = slip_open, 24662306a36Sopenharmony_ci .close = slip_close, 24762306a36Sopenharmony_ci .remove = NULL, 24862306a36Sopenharmony_ci .add_address = slip_add_addr, 24962306a36Sopenharmony_ci .delete_address = slip_del_addr, 25062306a36Sopenharmony_ci .mtu = BUF_SIZE, 25162306a36Sopenharmony_ci .max_packet = BUF_SIZE, 25262306a36Sopenharmony_ci}; 253