2 * Copyright (c) 2001, Adam Dunkels.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 * products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * This file is part of the uIP TCP/IP stack.
31 * $Id: tunslip.c,v 1.15 2008/02/24 21:13:36 adamdunkels Exp $
40 #include <sys/types.h>
47 #include <sys/ioctl.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
55 int ssystem(const char *fmt
, ...)
56 __attribute__((__format__ (__printf__
, 1, 2)));
57 void write_to_serial(int outfd
, void *inbuf
, int len
);
59 //#define PROGRESS(s) fprintf(stderr, s)
60 #define PROGRESS(s) do { } while (0)
63 u_int8_t ip_vhl
; /* version and header length */
67 u_int8_t ip_tos
; /* type of service */
68 u_int16_t ip_len
; /* total length */
69 u_int16_t ip_id
; /* identification */
70 u_int16_t ip_off
; /* fragment offset field */
71 #define IP_RF 0x8000 /* reserved fragment flag */
72 #define IP_DF 0x4000 /* dont fragment flag */
73 #define IP_MF 0x2000 /* more fragments flag */
74 #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
75 u_int8_t ip_ttl
; /* time to live */
76 u_int8_t ip_p
; /* protocol */
77 u_int16_t ip_sum
; /* checksum */
78 u_int32_t ip_src
, ip_dst
; /* source and dest address */
79 u_int16_t uh_sport
; /* source port */
80 u_int16_t uh_dport
; /* destination port */
81 u_int16_t uh_ulen
; /* udp length */
82 u_int16_t uh_sum
; /* udp checksum */
85 int check_ip(const struct ip
*ip
, unsigned ip_len
);
86 u_int16_t
ip4sum(u_int16_t sum
, const void *_p
, u_int16_t len
);
89 u_int8_t op
, htype
, hlen
, hops
;
91 u_int16_t secs
, flags
;
97 #define DHCP_BASE_LEN (4*7 + 16)
100 #define DHCP_HOLE_LEN (64 + 128)
101 #define DHCP_MSG_LEN (DHCP_BASE_LEN + DHCP_HOLE_LEN)
102 u_int8_t options
[312];
105 struct dhcp_light_msg
{
106 u_int8_t op
, htype
, hlen
, hops
;
108 u_int16_t secs
, flags
;
114 #define DHCP_LIGHT_MSG_LEN (4*7 + 16)
115 u_int8_t options
[312];
118 #define DHCP_OPTION_SUBNET_MASK 1
119 #define DHCP_OPTION_ROUTER 3
120 #define DHCP_OPTION_DNS_SERVER 6
121 #define DHCP_OPTION_REQ_IPADDR 50
122 #define DHCP_OPTION_LEASE_TIME 51
123 #define DHCP_OPTION_MSG_TYPE 53
124 #define DHCP_OPTION_SERVER_ID 54
125 #define DHCP_OPTION_REQ_LIST 55
126 #define DHCP_OPTION_AGENT 82
127 #define DHCP_OPTION_SUBNET_SELECTION 118
128 #define DHCP_OPTION_END 255
130 /* DHCP_OPTION_AGENT, Relay Agent Information option subtypes: */
131 #define RAI_CIRCUIT_ID 1
132 #define RAI_REMOTE_ID 2
133 #define RAI_AGENT_ID 3
134 #define RAI_SUBNET_SELECTION 5
136 #define DHCPDISCOVER 1
138 #define DHCPREQUEST 3
139 #define DHCPDECLINE 4
142 #define DHCPRELEASE 7
144 #define BOOTP_BROADCAST 0x8000
149 #define BOOTREQUEST 1
154 in_addr_t circuit_addr
;
156 char tundev
[32] = { "tun0" };
158 struct sockaddr_in dhaddr
;
162 relay_dhcp_to_server(struct ip
*ip
, int len
)
164 struct dhcp_light_msg
*inm
;
169 inm
= (void*)(((u_int8_t
*)ip
) + 20 + 8); /* Skip over IP&UDP headers. */
171 if (inm
->op
!= BOOTREQUEST
) {
175 inm
->flags
= ntohs(BOOTP_BROADCAST
);
177 memcpy(&m
, inm
, DHCP_BASE_LEN
);
178 memset(&m
.sname
, 0x0, DHCP_HOLE_LEN
);
179 memcpy(&m
.options
, &inm
->options
, len
- 20 - 8 - DHCP_BASE_LEN
);
180 n
= (len
- 20 - 8) + DHCP_HOLE_LEN
; /* +HOLE -IP&UDP headers. */
183 * Ideally we would like to use the Relay Agent information option
184 * (RFC3046) together with the Link Selection sub-option (RFC3527)
185 * to ensure that addresses are allocated for this
186 * subnet. Unfortunately ISC-DHCPD does not currently implement
187 * RFC3527 and some other mechanism must be used. For this reason
188 * this implementation in addition uses the DHCP option for subnet
189 * selection (RFC3011) which is really not intended to be used by
192 * Find DHCP_OPTION_END and add the new option here.
194 optptr
= &m
.options
[n
- DHCP_BASE_LEN
- DHCP_HOLE_LEN
- 1];
196 *optptr
++ = DHCP_OPTION_SUBNET_SELECTION
; /* RFC3011 */
198 memcpy(optptr
, &netaddr
, 4); optptr
+= 4;
202 *optptr
++ = DHCP_OPTION_AGENT
; /* RFC3046 */
203 *optptr
++ = 18; /* Sum of all suboptions below! */
205 *optptr
++ = RAI_SUBNET_SELECTION
; /* RFC3527 */
207 memcpy(optptr
, &netaddr
, 4); optptr
+= 4;
208 *optptr
++ = RAI_CIRCUIT_ID
;
210 memcpy(optptr
, &circuit_addr
, 4); optptr
+= 4;
211 *optptr
++ = RAI_AGENT_ID
;
213 memcpy(optptr
, &giaddr
, 4); optptr
+= 4;
214 n
+= 18 + 2; /* Sum of all suboptions + 2! */
216 /* And finally put back the END. */
217 *optptr
++ = DHCP_OPTION_END
;
220 memcpy(m
.giaddr
, &giaddr
, sizeof(m
.giaddr
));
221 if (n
!= sendto(dhsock
, &m
, n
, 0x0/*flags*/,
222 (struct sockaddr
*)&dhaddr
, sizeof(dhaddr
)))
223 err(1, "sendto relay failed");
226 static u_int16_t ip_id
;
229 relay_dhcp_to_client(int slipfd
)
234 struct dhcp_light_msg m
;
236 int n
, optlen
, ip_len
, udp_len
;
237 u_int8_t
*p
, *t
, *end
;
239 u_int8_t op
, msg_type
= 0;
240 struct in_addr yiaddr
;
242 memset(&inm
.options
, 0x0, sizeof(inm
.options
));
244 n
= recv(dhsock
, &inm
, sizeof(inm
), 0x0/*flags*/);
246 if (inm
.op
!= BOOTREPLY
) {
250 memcpy(&yiaddr
, inm
.yiaddr
, sizeof(inm
.yiaddr
));
251 memcpy(&pkt
.m
, &inm
, DHCP_BASE_LEN
);
253 memset(pkt
.m
.giaddr
, 0x0, sizeof(pkt
.m
.giaddr
));
256 * Copy options we would like to send to client.
258 memcpy(pkt
.m
.options
, inm
.options
, 4); /* Magic cookie */
261 p
= inm
.options
+ 4; /* Magic cookie */
262 t
= pkt
.m
.options
+ 4; /* Magic cookie */
266 case DHCP_OPTION_END
:
269 case DHCP_OPTION_MSG_TYPE
:
271 case DHCP_OPTION_SUBNET_MASK
:
272 case DHCP_OPTION_ROUTER
:
273 case DHCP_OPTION_LEASE_TIME
:
274 case DHCP_OPTION_SERVER_ID
: /* Copy these options */
275 memcpy(t
, p
, p
[1] + 2);
280 case DHCP_OPTION_DNS_SERVER
: /* Only copy first server */
283 memcpy(t
, p
+ 2, 4); t
+= 4;
287 default: /* Ignore these options */
288 /* printf("option type %d len %d\n", op, p[1]); */
294 if (op
== DHCP_OPTION_END
) {
298 optlen
= t
- pkt
.m
.options
;
299 ip_len
= 20 + 8 + DHCP_BASE_LEN
+ optlen
;
300 udp_len
= 8 + DHCP_BASE_LEN
+ optlen
;
302 pkt
.ip
.ip_vhl
= 0x45; /* IPv4 and hdrlen=5*4 */
304 pkt
.ip
.ip_len
= htons(ip_len
);
305 pkt
.ip
.ip_id
= htons(ip_id
++);
308 pkt
.ip
.ip_p
= 17; /* proto UDP */
310 pkt
.ip
.ip_src
= giaddr
;
311 if (inm
.flags
& htons(BOOTP_BROADCAST
)) /* check bcast bit */
312 pkt
.ip
.ip_dst
= 0xffffffff; /* 255.255.255.255 */
314 pkt
.ip
.ip_dst
= yiaddr
.s_addr
;
316 pkt
.ip
.uh_sport
= htons(BOOTPS
);
317 pkt
.ip
.uh_dport
= htons(BOOTPC
);
318 pkt
.ip
.uh_ulen
= htons(udp_len
);
321 pkt
.ip
.ip_sum
= ~htons(ip4sum(0, &pkt
.ip
, 20));
323 sum
= ip4sum(sum
, &pkt
.ip
.ip_src
, 8);
324 sum
= ip4sum(sum
, &pkt
.ip
.uh_sport
, udp_len
);
326 pkt
.ip
.uh_sum
= ~htons(sum
);
328 pkt
.ip
.uh_sum
= 0xffff;
330 write_to_serial(slipfd
, &pkt
, ip_len
);
331 if (msg_type
== DHCPACK
) {
332 printf("DHCPACK %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x IP %s\n",
333 pkt
.m
.chaddr
[0], pkt
.m
.chaddr
[1], pkt
.m
.chaddr
[2], pkt
.m
.chaddr
[3],
334 pkt
.m
.chaddr
[4], pkt
.m
.chaddr
[5], pkt
.m
.chaddr
[6], pkt
.m
.chaddr
[7],
336 /* ssystem("arp -s %s auto pub only", inet_ntoa(yiaddr)); */
341 * Internet checksum in host byte order.
344 ip4sum(u_int16_t sum
, const void *_p
, u_int16_t len
)
347 const u_int8_t
*p
= _p
;
348 const u_int8_t
*end
= p
+ len
;
351 t
= (p
[0] << 8) + p
[1];
365 check_ip(const struct ip
*ip
, unsigned ip_len
)
367 u_int16_t sum
, ip_hl
;
369 /* Check IP version and length. */
370 if((ip
->ip_vhl
& IP_V
) != IP_V4
)
373 if(ntohs(ip
->ip_len
) > ip_len
)
376 if(ntohs(ip
->ip_len
) < ip_len
)
379 /* Check IP header. */
380 ip_hl
= 4*(ip
->ip_vhl
& IP_HL
);
381 sum
= ip4sum(0, ip
, ip_hl
);
382 if(sum
!= 0xffff && sum
!= 0x0)
385 if(ip
->ip_p
== 6 || ip
->ip_p
== 17) { /* Check TCP or UDP header. */
386 u_int16_t tcp_len
= ip_len
- ip_hl
;
388 /* Sum pseudoheader. */
389 sum
= ip
->ip_p
+ tcp_len
; /* proto and len, no carry */
390 sum
= ip4sum(sum
, &ip
->ip_src
, 8); /* src and dst */
392 /* Sum TCP/UDP header and data. */
393 sum
= ip4sum(sum
, (u_int8_t
*)ip
+ ip_hl
, tcp_len
);
395 /* Failed checksum test? */
396 if (sum
!= 0xffff && sum
!= 0x0) {
397 if (ip
->ip_p
== 6) { /* TCP == 6 */
400 /* Deal with disabled UDP checksums. */
405 } else if (ip
->ip_p
== 1) { /* ICMP */
406 u_int16_t icmp_len
= ip_len
- ip_hl
;
408 sum
= ip4sum(0, (u_int8_t
*)ip
+ ip_hl
, icmp_len
);
409 if(sum
!= 0xffff && sum
!= 0x0)
416 is_sensible_string(const unsigned char *s
, int len
)
419 for(i
= 1; i
< len
; i
++) {
420 if(s
[i
] == 0 || s
[i
] == '\r' || s
[i
] == '\n' || s
[i
] == '\t') {
422 } else if(s
[i
] < ' ' || '~' < s
[i
]) {
430 ssystem(const char *fmt
, ...) __attribute__((__format__ (__printf__
, 1, 2)));
433 ssystem(const char *fmt
, ...)
438 vsnprintf(cmd
, sizeof(cmd
), fmt
, ap
);
445 #define SLIP_END 0300
446 #define SLIP_ESC 0333
447 #define SLIP_ESC_END 0334
448 #define SLIP_ESC_ESC 0335
451 * Read from serial, when we have a packet write it to tun. No output
452 * buffering, input buffered by stdio.
455 serial_to_tun(FILE *inslip
, int outfd
)
458 unsigned char inbuf
[2000];
461 static int inbufptr
= 0;
467 ret
= fread(&c
, 1, 1, inslip
);
468 if(ret
== -1 || ret
== 0) err(1, "serial_to_tun: read");
473 if(inbufptr
>= sizeof(uip
.inbuf
)) {
476 ret
= fread(&c
, 1, 1, inslip
);
481 err(1, "serial_to_tun: read");
486 fprintf(stderr
, "serial_to_tun: EOF\n");
489 /* fprintf(stderr, ".");*/
496 #define DEBUG_LINE_MARKER '\r'
498 ecode
= check_ip(&uip
.iphdr
, inbufptr
);
499 if(ecode
< 0 && inbufptr
== 8 && strncmp(uip
.inbuf
, "=IPA", 4) == 0) {
500 static struct in_addr ipa
;
503 if(memcmp(&ipa
, &uip
.inbuf
[4], sizeof(ipa
)) == 0) {
508 if(ipa
.s_addr
!= 0) {
510 ssystem("route delete -net %s netmask %s dev %s",
511 inet_ntoa(ipa
), "255.255.255.255", tundev
);
513 ssystem("route delete -net %s -netmask %s -interface %s",
514 inet_ntoa(ipa
), "255.255.255.255", tundev
);
518 memcpy(&ipa
, &uip
.inbuf
[4], sizeof(ipa
));
519 if(ipa
.s_addr
!= 0) {
521 ssystem("route add -net %s netmask %s dev %s",
522 inet_ntoa(ipa
), "255.255.255.255", tundev
);
524 ssystem("route add -net %s -netmask %s -interface %s",
525 inet_ntoa(ipa
), "255.255.255.255", tundev
);
529 } else if(ecode
< 0) {
531 * If sensible ASCII string, print it as debug info!
533 if(uip
.inbuf
[0] == DEBUG_LINE_MARKER
) {
534 fwrite(uip
.inbuf
+ 1, inbufptr
- 1, 1, stderr
);
535 } else if(is_sensible_string(uip
.inbuf
, inbufptr
)) {
536 fwrite(uip
.inbuf
, inbufptr
, 1, stderr
);
539 "serial_to_tun: drop packet len=%d ecode=%d\n",
548 struct ip
*ip
= (void *)uip
.inbuf
;
549 if(ip
->ip_p
== 17 && ip
->ip_dst
== 0xffffffff /* UDP and broadcast */
550 && ip
->uh_sport
== ntohs(BOOTPC
) && ip
->uh_dport
== ntohs(BOOTPS
)) {
551 relay_dhcp_to_server(ip
, inbufptr
);
555 if(write(outfd
, uip
.inbuf
, inbufptr
) != inbufptr
) {
556 err(1, "serial_to_tun: write");
563 if(fread(&c
, 1, 1, inslip
) != 1) {
565 /* Put ESC back and give up! */
566 ungetc(SLIP_ESC
, inslip
);
580 uip
.inbuf
[inbufptr
++] = c
;
587 unsigned char slip_buf
[2000];
588 int slip_end
, slip_begin
;
591 slip_send(int fd
, unsigned char c
)
593 if (slip_end
>= sizeof(slip_buf
))
594 err(1, "slip_send overflow");
595 slip_buf
[slip_end
] = c
;
602 return slip_end
== 0;
606 slip_flushbuf(int fd
)
613 n
= write(fd
, slip_buf
+ slip_begin
, (slip_end
- slip_begin
));
615 if(n
== -1 && errno
!= EAGAIN
) {
616 err(1, "slip_flushbuf write failed");
618 PROGRESS("Q"); /* Outqueueis full! */
621 if(slip_begin
== slip_end
) {
622 slip_begin
= slip_end
= 0;
628 write_to_serial(int outfd
, void *inbuf
, int len
)
632 struct ip
*iphdr
= inbuf
;
637 ecode
= check_ip(inbuf
, len
);
639 fprintf(stderr
, "tun_to_serial: drop packet %d\n", ecode
);
643 if(iphdr
->ip_id
== 0 && iphdr
->ip_off
& IP_DF
) {
644 uint16_t nid
= htons(ip_id
++);
646 nid
= ~nid
; /* negate */
647 iphdr
->ip_sum
+= nid
; /* add */
648 if(iphdr
->ip_sum
< nid
) { /* 1-complement overflow? */
651 ecode
= check_ip(inbuf
, len
);
653 fprintf(stderr
, "tun_to_serial: drop packet %d\n", ecode
);
658 /* It would be ``nice'' to send a SLIP_END here but it's not
661 /* slip_send(outfd, SLIP_END); */
663 for(i
= 0; i
< len
; i
++) {
666 slip_send(outfd
, SLIP_ESC
);
667 slip_send(outfd
, SLIP_ESC_END
);
670 slip_send(outfd
, SLIP_ESC
);
671 slip_send(outfd
, SLIP_ESC_ESC
);
674 slip_send(outfd
, p
[i
]);
679 slip_send(outfd
, SLIP_END
);
685 * Read from tun, write to slip.
688 tun_to_serial(int infd
, int outfd
)
691 unsigned char inbuf
[2000];
696 if((size
= read(infd
, uip
.inbuf
, 2000)) == -1) err(1, "tun_to_serial: read");
698 write_to_serial(outfd
, uip
.inbuf
, size
);
702 #define BAUDRATE B115200
704 speed_t b_rate
= BAUDRATE
;
710 speed_t speed
= b_rate
;
713 if(tcflush(fd
, TCIOFLUSH
) == -1) err(1, "tcflush");
715 if(tcgetattr(fd
, &tty
) == -1) err(1, "tcgetattr");
719 /* Nonblocking read. */
722 tty
.c_cflag
&= ~CRTSCTS
;
723 tty
.c_cflag
&= ~HUPCL
;
724 tty
.c_cflag
&= ~CLOCAL
;
726 cfsetispeed(&tty
, speed
);
727 cfsetospeed(&tty
, speed
);
729 if(tcsetattr(fd
, TCSAFLUSH
, &tty
) == -1) err(1, "tcsetattr");
732 /* Nonblocking read and write. */
733 /* if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */
735 tty
.c_cflag
|= CLOCAL
;
736 if(tcsetattr(fd
, TCSAFLUSH
, &tty
) == -1) err(1, "tcsetattr");
739 if(ioctl(fd
, TIOCMBIS
, &i
) == -1) err(1, "ioctl");
742 usleep(10*1000); /* Wait for hardware 10ms. */
744 /* Flush input and output buffers. */
745 if(tcflush(fd
, TCIOFLUSH
) == -1) err(1, "tcflush");
749 devopen(const char *dev
, int flags
)
754 return open(t
, flags
);
758 #include <linux/if.h>
759 #include <linux/if_tun.h>
767 if( (fd
= open("/dev/net/tun", O_RDWR
)) < 0 )
770 memset(&ifr
, 0, sizeof(ifr
));
772 /* Flags: IFF_TUN - TUN device (no Ethernet headers)
773 * IFF_TAP - TAP device
775 * IFF_NO_PI - Do not provide packet information
777 ifr
.ifr_flags
= IFF_TUN
| IFF_NO_PI
;
779 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
781 if((err
= ioctl(fd
, TUNSETIFF
, (void *) &ifr
)) < 0 ){
785 strcpy(dev
, ifr
.ifr_name
);
792 return devopen(dev
, O_RDWR
);
802 ssystem("ifconfig %s down", tundev
);
804 ssystem("sysctl -w net.inet.ip.forwarding=0");
806 /* ssystem("arp -d %s", ipaddr); */
807 ssystem("netstat -nr"
808 " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'"
814 sigcleanup(int signo
)
816 fprintf(stderr
, "signal %d\n", signo
);
817 exit(0); /* exit(0) will call cleanup() */
820 static int got_sigalarm
;
833 #define TIMEOUT (997*1000)
835 #define TIMEOUT (2451*1000)
837 ualarm(TIMEOUT
, TIMEOUT
);
842 ifconf(const char *tundev
, const char *ipaddr
, const char *netmask
)
844 struct in_addr netname
;
845 netname
.s_addr
= inet_addr(ipaddr
) & inet_addr(netmask
);
848 ssystem("ifconfig %s inet `hostname` up", tundev
);
849 if(strcmp(ipaddr
, "0.0.0.0") != 0) {
850 ssystem("route add -net %s netmask %s dev %s",
851 inet_ntoa(netname
), netmask
, tundev
);
854 ssystem("ifconfig %s inet `hostname` %s up", tundev
, ipaddr
);
855 if(strcmp(ipaddr
, "0.0.0.0") != 0) {
856 ssystem("route add -net %s -netmask %s -interface %s",
857 inet_ntoa(netname
), netmask
, tundev
);
859 ssystem("sysctl -w net.inet.ip.forwarding=1");
862 ssystem("ifconfig %s\n", tundev
);
866 main(int argc
, char **argv
)
869 int tunfd
, slipfd
, maxfd
;
873 const char *siodev
= NULL
;
874 const char *dhcp_server
= NULL
;
875 u_int16_t myport
= BOOTPS
, dhport
= BOOTPS
;
878 ip_id
= getpid() * time(NULL
);
880 setvbuf(stdout
, NULL
, _IOLBF
, 0); /* Line buffered output. */
882 while((c
= getopt(argc
, argv
, "B:D:hs:t:")) != -1) {
885 baudrate
= atoi(optarg
);
889 dhcp_server
= optarg
;
893 if(strncmp("/dev/", optarg
, 5) == 0) {
901 if(strncmp("/dev/", optarg
, 5) == 0) {
902 strcpy(tundev
, optarg
+ 5);
904 strcpy(tundev
, optarg
);
911 err(1, "usage: tunslip [-B baudrate] [-s siodev] [-t tundev] [-D dhcp-server] ipaddress netmask [dhcp-server]");
915 argc
-= (optind
- 1);
916 argv
+= (optind
- 1);
918 if(argc
!= 3 && argc
!= 4) {
919 err(1, "usage: tunslip [-s siodev] [-t tundev] [-D dhcp-server] ipaddress netmask [dhcp-server]");
923 circuit_addr
= inet_addr(ipaddr
);
924 netaddr
= inet_addr(ipaddr
) & inet_addr(netmask
);
928 break; /* Use default. */
945 err(1, "unknown baudrate %d", baudrate
);
950 * Set up DHCP relay agent socket and find the address of this relay
954 dhcp_server
= argv
[3];
956 if(dhcp_server
!= NULL
) {
957 struct sockaddr_in myaddr
;
961 if(strchr(dhcp_server
, ':') != NULL
) {
962 dhport
= atoi(strchr(dhcp_server
, ':') + 1);
964 *strchr(dhcp_server
, ':') = '\0';
966 a
= inet_addr(dhcp_server
);
968 err(1, "illegal dhcp-server address");
971 dhaddr
.sin_len
= sizeof(dhaddr
);
973 dhaddr
.sin_family
= AF_INET
;
974 dhaddr
.sin_port
= htons(dhport
);
975 dhaddr
.sin_addr
.s_addr
= a
;
977 dhsock
= socket(AF_INET
, SOCK_DGRAM
, 0);
981 memset(&myaddr
, 0x0, sizeof(myaddr
));
983 myaddr
.sin_len
= sizeof(myaddr
);
985 myaddr
.sin_family
= AF_INET
;
986 myaddr
.sin_addr
.s_addr
= INADDR_ANY
;
987 myaddr
.sin_port
= htons(myport
);
988 if(bind(dhsock
, (struct sockaddr
*)&myaddr
, sizeof(myaddr
)) < 0) {
989 err(1, "bind dhcp-relay");
992 if(connect(dhsock
, (struct sockaddr
*)&dhaddr
, sizeof(dhaddr
)) < 0) {
993 err(1, "connect to dhcp-server");
996 len
= sizeof(myaddr
);
997 if(getsockname(dhsock
, (struct sockaddr
*)&myaddr
, &len
) < 0) {
998 err(1, "getsockname dhsock");
1001 giaddr
= myaddr
.sin_addr
.s_addr
;
1004 * Don't want connected socket.
1007 dhsock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1011 myaddr
.sin_family
= AF_INET
;
1012 myaddr
.sin_addr
.s_addr
= INADDR_ANY
;
1013 myaddr
.sin_port
= htons(myport
);
1014 if(bind(dhsock
, (struct sockaddr
*)&myaddr
, sizeof(myaddr
)) < 0) {
1015 err(1, "bind dhcp-relay");
1017 fprintf(stderr
, "DHCP server at %s:%d\n", dhcp_server
, dhport
);
1020 if(siodev
!= NULL
) {
1021 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
1023 err(1, "can't open siodev ``/dev/%s''", siodev
);
1026 static const char *siodevs
[] = {
1027 "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */
1030 for(i
= 0; i
< 3; i
++) {
1031 siodev
= siodevs
[i
];
1032 slipfd
= devopen(siodev
, O_RDWR
| O_NONBLOCK
);
1037 err(1, "can't open siodev");
1040 fprintf(stderr
, "slip started on ``/dev/%s''\n", siodev
);
1042 slip_send(slipfd
, SLIP_END
);
1043 inslip
= fdopen(slipfd
, "r");
1044 if(inslip
== NULL
) err(1, "main: fdopen");
1046 tunfd
= tun_alloc(tundev
);
1047 if(tunfd
== -1) err(1, "main: open");
1048 fprintf(stderr
, "opened device ``/dev/%s''\n", tundev
);
1051 signal(SIGHUP
, sigcleanup
);
1052 signal(SIGTERM
, sigcleanup
);
1053 signal(SIGINT
, sigcleanup
);
1054 signal(SIGALRM
, sigalarm
);
1055 ifconf(tundev
, ipaddr
, netmask
);
1064 slip_send(slipfd
, '?');
1065 slip_send(slipfd
, 'I');
1066 slip_send(slipfd
, 'P');
1067 slip_send(slipfd
, 'A');
1068 slip_send(slipfd
, SLIP_END
);
1072 if(!slip_empty()) { /* Anything to flush? */
1073 FD_SET(slipfd
, &wset
);
1076 FD_SET(slipfd
, &rset
); /* Read from slip ASAP! */
1077 if(slipfd
> maxfd
) maxfd
= slipfd
;
1079 /* We only have one packet at a time queued for slip output. */
1081 FD_SET(tunfd
, &rset
);
1082 if(tunfd
> maxfd
) maxfd
= tunfd
;
1084 FD_SET(dhsock
, &rset
);
1085 if(dhsock
> maxfd
) maxfd
= dhsock
;
1089 ret
= select(maxfd
+ 1, &rset
, &wset
, NULL
, NULL
);
1090 if(ret
== -1 && errno
!= EINTR
) {
1092 } else if(ret
> 0) {
1093 if(FD_ISSET(slipfd
, &rset
)) {
1094 serial_to_tun(inslip
, tunfd
);
1097 if(FD_ISSET(slipfd
, &wset
)) {
1098 slip_flushbuf(slipfd
);
1102 if(slip_empty() && FD_ISSET(tunfd
, &rset
)) {
1103 tun_to_serial(tunfd
, slipfd
);
1104 slip_flushbuf(slipfd
);
1108 if(dhsock
!= -1 && slip_empty() && FD_ISSET(dhsock
, &rset
)) {
1109 relay_dhcp_to_client(slipfd
);
1110 slip_flushbuf(slipfd
);