}p=redir_str;if(get_str_sep(buf,sizeof(buf),&p,':')<0)gotofail;if(!strcmp(buf,"tcp")){is_udp=0;}elseif(!strcmp(buf,"udp")){is_udp=1;}else{gotofail;}if(get_str_sep(buf,sizeof(buf),&p,':')<0)gotofail;host_port=strtol(buf,&r,0);if(r==buf)gotofail;if(get_str_sep(buf,sizeof(buf),&p,':')<0)gotofail;if(buf[0]=='\0'){pstrcpy(buf,sizeof(buf),"10.0.2.15");}if(!inet_aton(buf,&guest_addr))gotofail;guest_port=strtol(p,&r,0);if(r==p)gotofail;if(slirp_redir(is_udp,host_port,guest_addr,guest_port)<0){fprintf(stderr,"qemu: could not set up redirection\n");exit(1);}return;fail:fprintf(stderr,"qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");exit(1);}#ifndef_WIN32staticcharsmb_dir[1024];staticvoiderase_dir(char*dir_name){DIR*d;structdirent*de;charfilename[1024];/* erase all the files in the directory */if((d=opendir(dir_name))!=0){for(;;){de=readdir(d);if(!de)break;if(strcmp(de->d_name,".")!=0&&strcmp(de->d_name,"..")!=0){snprintf(filename,sizeof(filename),"%s/%s",smb_dir,de->d_name);if(unlink(filename)!=0)/* is it a directory? */erase_dir(filename);}}closedir(d);rmdir(dir_name);}}/* automatic user mode samba server configuration */staticvoidsmb_exit(void){erase_dir(smb_dir);}/* automatic user mode samba server configuration */voidnet_slirp_smb(constchar*exported_dir){charsmb_conf[1024];charsmb_cmdline[1024];FILE*f;if(!slirp_inited){slirp_inited=1;
}/* XXX: better tmp dir construction */snprintf(smb_dir,sizeof(smb_dir),"/tmp/qemu-smb.%d",getpid());if(mkdir(smb_dir,0700)<0){fprintf(stderr,"qemu: could not create samba server dir '%s'\n",smb_dir);exit(1);}snprintf(smb_conf,sizeof(smb_conf),"%s/%s",smb_dir,"smb.conf");f=fopen(smb_conf,"w");if(!f){fprintf(stderr,"qemu: could not create samba server configuration file '%s'\n",smb_conf);exit(1);}fprintf(f,"[global]\n""private dir=%s\n""smb ports=0\n""socket address=127.0.0.1\n""pid directory=%s\n""lock directory=%s\n""log file=%s/log.smbd\n""smb passwd file=%s/smbpasswd\n""security = share\n""[qemu]\n""path=%s\n""read only=no\n""guest ok=yes\n",smb_dir,smb_dir,smb_dir,smb_dir,smb_dir,exported_dir);fclose(f);atexit(smb_exit);snprintf(smb_cmdline,sizeof(smb_cmdline),"%s -s %s",SMBD_COMMAND,smb_conf);slirp_add_exec(0,smb_cmdline,4,139);}#endif/* !defined(_WIN32) */voiddo_info_slirp(void){slirp_stats();}#endif/* CONFIG_SLIRP */#if!defined(_WIN32)typedefstructTAPState{VLANClientState*vc;intfd;chardown_script[1024];
staticvoidtap_receive(void*opaque,constuint8_t*buf,intsize){TAPState*s=opaque;intret;for(;;){ret=write(s->fd,buf,size);if(ret<0&&(errno==EINTR||errno==EAGAIN)){}else{break;}}}staticvoidtap_send(void*opaque){TAPState*s=opaque;uint8_tbuf[4096];intsize;#ifdef__sun__structstrbufsbuf;intf=0;sbuf.maxlen=sizeof(buf);sbuf.buf=buf;size=getmsg(s->fd,NULL,&sbuf,&f)>=0?sbuf.len:-1;#elsesize=read(s->fd,buf,sizeof(buf));#endifif(size>0){qemu_send_packet(s->vc,buf,size);}}/* fd support */
returns;}#ifdefined(_BSD)||defined(__FreeBSD_kernel__)staticinttap_open(char*ifname,intifname_size){intfd;char*dev;structstats;TFR(fd=open("/dev/tap",O_RDWR));if(fd<0){fprintf(stderr,"warning: could not open /dev/tap: no virtual network emulation\n");return-1;}fstat(fd,&s);dev=devname(s.st_rdev,S_IFCHR);pstrcpy(ifname,ifname_size,dev);fcntl(fd,F_SETFL,O_NONBLOCK);returnfd;}#elifdefined(__sun__)#defineTUNNEWPPA(('T'<<16)|0x0001)/**AllocateTAPdevice,returnsopenedfd.*Storesdevnameinthefirstarg(mustbelargeenough).*/inttap_alloc(char*dev,size_tdev_size){inttap_fd,if_fd,ppa=-1;staticintip_fd=0;char*ptr;staticintarp_fd=0;intip_muxid,arp_muxid;structstrioctlstrioc_if,strioc_ppa;intlink_type=I_PLINK;;structlifreqifr;charactual_name[32]="";memset(&ifr,0x0,sizeof(ifr));if(*dev){ptr=dev;
ppa=atoi(ptr);}/* Check if IP device was opened */if(ip_fd)close(ip_fd);TFR(ip_fd=open("/dev/udp",O_RDWR,0));if(ip_fd<0){syslog(LOG_ERR,"Can't open /dev/ip (actually /dev/udp)");return-1;}TFR(tap_fd=open("/dev/tap",O_RDWR,0));if(tap_fd<0){syslog(LOG_ERR,"Can't open /dev/tap");return-1;}/* Assign a new PPA and get its unit number. */strioc_ppa.ic_cmd=TUNNEWPPA;strioc_ppa.ic_timout=0;strioc_ppa.ic_len=sizeof(ppa);strioc_ppa.ic_dp=(char*)&ppa;if((ppa=ioctl(tap_fd,I_STR,&strioc_ppa))<0)syslog(LOG_ERR,"Can't assign new interface");TFR(if_fd=open("/dev/tap",O_RDWR,0));if(if_fd<0){syslog(LOG_ERR,"Can't open /dev/tap (2)");return-1;}if(ioctl(if_fd,I_PUSH,"ip")<0){syslog(LOG_ERR,"Can't push IP module");return-1;}if(ioctl(if_fd,SIOCGLIFFLAGS,&ifr)<0)syslog(LOG_ERR,"Can't get flags\n");snprintf(actual_name,32,"tap%d",ppa);pstrcpy(ifr.lifr_name,sizeof(ifr.lifr_name),actual_name);ifr.lifr_ppa=ppa;/* Assign ppa according to the unit number returned by tun device */if(ioctl(if_fd,SIOCSLIFNAME,&ifr)<0)syslog(LOG_ERR,"Can't set PPA %d",ppa);if(ioctl(if_fd,SIOCGLIFFLAGS,&ifr)<0)syslog(LOG_ERR,"Can't get flags\n");/* Push arp module to if_fd */if(ioctl(if_fd,I_PUSH,"arp")<0)syslog(LOG_ERR,"Can't push ARP module (2)");/* Push arp module to ip_fd */if(ioctl(ip_fd,I_POP,NULL)<0)syslog(LOG_ERR,"I_POP failed\n");if(ioctl(ip_fd,I_PUSH,"arp")<0)syslog(LOG_ERR,"Can't push ARP module (3)\n");/* Open arp_fd */TFR(arp_fd=open("/dev/tap",O_RDWR,0));if(arp_fd<0)syslog(LOG_ERR,"Can't open %s\n","/dev/tap");/* Set ifname to arp */strioc_if.ic_cmd=SIOCSLIFNAME;strioc_if.ic_timout=0;strioc_if.ic_len=sizeof(ifr);strioc_if.ic_dp=(char*)𝔦if(ioctl(arp_fd,I_STR,&strioc_if)<0){syslog(LOG_ERR,"Can't set ifname to arp\n");}if((ip_muxid=ioctl(ip_fd,I_LINK,if_fd))<0){syslog(LOG_ERR,"Can't link TAP device to IP");return-1;}if((arp_muxid=ioctl(ip_fd,link_type,arp_fd))<0)syslog(LOG_ERR,"Can't link TAP device to ARP");close(if_fd);memset(&ifr,0x0,sizeof(ifr));pstrcpy(ifr.lifr_name,sizeof(ifr.lifr_name),actual_name);ifr.lifr_ip_muxid=ip_muxid;ifr.lifr_arp_muxid=arp_muxid;if(ioctl(ip_fd,SIOCSLIFMUXID,&ifr)<0){ioctl(ip_fd,I_PUNLINK,arp_muxid);ioctl(ip_fd,I_PUNLINK,ip_muxid);syslog(LOG_ERR,"Can't set multiplexor id");}snprintf(dev,dev_size,"tap%d",ppa);returntap_fd;}staticinttap_open(char*ifname,intifname_size){chardev[10]="";intfd;if((fd=tap_alloc(dev,sizeof(dev)))<0){fprintf(stderr,"Cannot allocate TAP device\n");return-1;}pstrcpy(ifname,ifname_size,dev);fcntl(fd,F_SETFL,O_NONBLOCK);returnfd;}
#elsestaticinttap_open(char*ifname,intifname_size){structifreqifr;intfd,ret;TFR(fd=open("/dev/net/tun",O_RDWR));if(fd<0){fprintf(stderr,"warning: could not open /dev/net/tun: no virtual network emulation\n");return-1;}memset(&ifr,0,sizeof(ifr));ifr.ifr_flags=IFF_TAP|IFF_NO_PI;if(ifname[0]!='\0')pstrcpy(ifr.ifr_name,IFNAMSIZ,ifname);elsepstrcpy(ifr.ifr_name,IFNAMSIZ,"tap%d");ret=ioctl(fd,TUNSETIFF,(void*)&ifr);if(ret!=0){fprintf(stderr,"warning: could not configure /dev/net/tun: no virtual network emulation\n");close(fd);return-1;}pstrcpy(ifname,ifname_size,ifr.ifr_name);fcntl(fd,F_SETFL,O_NONBLOCK);returnfd;}#endifstaticintlaunch_script(constchar*setup_script,constchar*ifname,intfd){intpid,status;char*args[3];char**parg;/* try to launch network script */pid=fork();if(pid>=0){if(pid==0){intopen_max=sysconf(_SC_OPEN_MAX),i;for(i=0;i<open_max;i++)if(i!=STDIN_FILENO&&i!=STDOUT_FILENO&&i!=STDERR_FILENO&&i!=fd)close(i);parg=args;*parg++=(char*)setup_script;*parg++=(char*)ifname;*parg++=NULL;execv(setup_script,args);_exit(1);}while(waitpid(pid,&status,0)!=pid);if(!WIFEXITED(status)||WEXITSTATUS(status)!=0){fprintf(stderr,"%s: could not launch network script\n",setup_script);return-1;}}return0;}
intfd;}NetSocketListenState;/* XXX: we consider we can send the whole packet without blocking */staticvoidnet_socket_receive(void*opaque,constuint8_t*buf,intsize){NetSocketState*s=opaque;uint32_tlen;len=htonl(size);send_all(s->fd,(constuint8_t*)&len,sizeof(len));send_all(s->fd,buf,size);}staticvoidnet_socket_receive_dgram(void*opaque,constuint8_t*buf,intsize){NetSocketState*s=opaque;sendto(s->fd,buf,size,0,(structsockaddr*)&s->dgram_dst,sizeof(s->dgram_dst));}staticvoidnet_socket_send(void*opaque){NetSocketState*s=opaque;intl,size,err;uint8_tbuf1[4096];constuint8_t*buf;size=recv(s->fd,buf1,sizeof(buf1),0);if(size<0){err=socket_error();if(err!=EWOULDBLOCK)gotoeoc;}elseif(size==0){/* end of connection */eoc:qemu_set_fd_handler(s->fd,NULL,NULL,NULL);closesocket(s->fd);return;}buf=buf1;while(size>0){/* reassemble a packet from the network */switch(s->state){case0:l=4-s->index;if(l>size)l=size;memcpy(s->buf+s->index,buf,l);buf+=l;size-=l;s->index+=l;if(s->index==4){/* got length */s->packet_len=ntohl(*(uint32_t*)s->buf);s->index=0;s->state=1;}break;case1:l=s->packet_len-s->index;if(l>size)l=size;memcpy(s->buf+s->index,buf,l);s->index+=l;buf+=l;size-=l;if(s->index>=s->packet_len){qemu_send_packet(s->vc,s->buf,s->packet_len);s->index=0;s->state=0;}break;}}}staticvoidnet_socket_send_dgram(void*opaque){NetSocketState*s=opaque;intsize;size=recv(s->fd,s->buf,sizeof(s->buf),0);if(size<0)return;if(size==0){/* end of connection */qemu_set_fd_handler(s->fd,NULL,NULL,NULL);return;}qemu_send_packet(s->vc,s->buf,size);}staticintnet_socket_mcast_create(structsockaddr_in*mcastaddr){structip_mreqimr;intfd;intval,ret;if(!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))){fprintf(stderr,"qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",inet_ntoa(mcastaddr->sin_addr),(int)ntohl(mcastaddr->sin_addr.s_addr));return-1;}fd=socket(PF_INET,SOCK_DGRAM,0);if(fd<0){perror("socket(PF_INET, SOCK_DGRAM)");return-1;}val=1;ret=setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(constchar*)&val,sizeof(val));if(ret<0){perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");gotofail;}ret=bind(fd,(structsockaddr*)mcastaddr,sizeof(*mcastaddr));if(ret<0){perror("bind");gotofail;}/* Add host to multicast group */imr.imr_multiaddr=mcastaddr->sin_addr;imr.imr_interface.s_addr=htonl(INADDR_ANY);ret=setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(constchar*)&imr,sizeof(structip_mreq));if(ret<0){perror("setsockopt(IP_ADD_MEMBERSHIP)");gotofail;}/* Force mcast msgs to loopback (eg. several QEMUs in same host */val=1;ret=setsockopt(fd,IPPROTO_IP,IP_MULTICAST_LOOP,(constchar*)&val,sizeof(val));if(ret<0){perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");gotofail;}socket_set_nonblock(fd);returnfd;fail:if(fd>=0)closesocket(fd);return-1;}
default:/* who knows ... this could be a eg. a pty, do warn and continue as stream */fprintf(stderr,"qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n",so_type,fd);
if(!s1){closesocket(fd);}else{snprintf(s1->vc->info_str,sizeof(s1->vc->info_str),"socket: connection from %s:%d",inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port));}}
{NetSocketListenState*s;intfd,val,ret;structsockaddr_insaddr;if(parse_host_port(&saddr,host_str)<0)return-1;s=qemu_mallocz(sizeof(NetSocketListenState));if(!s)return-1;fd=socket(PF_INET,SOCK_STREAM,0);if(fd<0){perror("socket");return-1;}socket_set_nonblock(fd);/* allow fast reuse */val=1;setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(constchar*)&val,sizeof(val));ret=bind(fd,(structsockaddr*)&saddr,sizeof(saddr));if(ret<0){perror("bind");return-1;}ret=listen(fd,0);if(ret<0){perror("listen");return-1;}s->vlan=vlan;
if(!s)return-1;s->dgram_dst=saddr;snprintf(s->vc->info_str,sizeof(s->vc->info_str),"socket: mcast=%s:%d",inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port));return0;}/* find or alloc a new VLAN */VLANState*qemu_find_vlan(intid){VLANState**pvlan,*vlan;for(vlan=first_vlan;vlan!=NULL;vlan=vlan->next){if(vlan->id==id)returnvlan;}vlan=qemu_mallocz(sizeof(VLANState));if(!vlan)returnNULL;vlan->id=id;vlan->next=NULL;pvlan=&first_vlan;while(*pvlan!=NULL)pvlan=&(*pvlan)->next;*pvlan=vlan;returnvlan;}
voidqemu_check_nic_model(NICInfo*nd,constchar*model){constchar*models[2];models[0]=model;models[1]=NULL;qemu_check_nic_model_list(nd,models,model);}voidqemu_check_nic_model_list(NICInfo*nd,constchar*const*models,constchar*default_model){inti,exit_status=0;if(!nd->model)nd->model=strdup(default_model);if(strcmp(nd->model,"?")!=0){for(i=0;models[i];i++)if(strcmp(nd->model,models[i])==0)return;fprintf(stderr,"qemu: Unsupported NIC model: %s\n",nd->model);exit_status=1;}fprintf(stderr,"qemu: Supported NIC models: ");for(i=0;models[i];i++)fprintf(stderr,"%s%c",models[i],models[i+1]?',':'\n');exit(exit_status);}
vlan_id=0;if(get_param_value(buf,sizeof(buf),"vlan",p)){vlan_id=strtol(buf,NULL,0);}vlan=qemu_find_vlan(vlan_id);if(!vlan){fprintf(stderr,"Could not create vlan %d\n",vlan_id);return-1;}
if(!strcmp(device,"nic")){NICInfo*nd;uint8_t*macaddr;if(nb_nics>=MAX_NICS){fprintf(stderr,"Too Many NICs\n");return-1;}nd=&nd_table[nb_nics];macaddr=nd->macaddr;macaddr[0]=0x52;macaddr[1]=0x54;macaddr[2]=0x00;macaddr[3]=0x12;macaddr[4]=0x34;macaddr[5]=0x56+nb_nics;if(get_param_value(buf,sizeof(buf),"macaddr",p)){if(parse_macaddr(macaddr,buf)<0){fprintf(stderr,"invalid syntax for ethernet address\n");return-1;}}if(get_param_value(buf,sizeof(buf),"model",p)){nd->model=strdup(buf);}nd->vlan=vlan;
}else#endif#ifdef_WIN32if(!strcmp(device,"tap")){charifname[64];if(get_param_value(ifname,sizeof(ifname),"ifname",p)<=0){fprintf(stderr,"tap: no interface name\n");return-1;}vlan->nb_host_devs++;
if(!vc){term_printf("could not find network device '%s'",name);return0;}if(strcmp(up_or_down,"up")==0)vc->link_down=0;elseif(strcmp(up_or_down,"down")==0)vc->link_down=1;elseterm_printf("invalid link status '%s'; only 'up' or 'down' valid\n",up_or_down);
voidnet_cleanup(void){VLANState*vlan;#if!defined(_WIN32)/* close network clients */for(vlan=first_vlan;vlan!=NULL;vlan=vlan->next){VLANClientState*vc;for(vc=vlan->first_client;vc!=NULL;vc=vc->next){if(vc->fd_read==tap_receive){TAPState*s=vc->opaque;
}#ifdefined(CONFIG_VDE)if(vc->fd_read==vde_from_qemu){VDEState*s=vc->opaque;vde_close(s->vde);}#endif}}#endif}voidnet_client_check(void){VLANState*vlan;for(vlan=first_vlan;vlan!=NULL;vlan=vlan->next){if(vlan->nb_guest_devs==0&&vlan->nb_host_devs==0)continue;if(vlan->nb_guest_devs==0)fprintf(stderr,"Warning: vlan %d with no nics\n",vlan->id);if(vlan->nb_host_devs==0)fprintf(stderr,"Warning: vlan %d is not connected to host network\n",vlan->id);}}