├── COPYING ├── DCO ├── Makefile.am ├── README.md ├── can.c ├── commands.c ├── commands_fsl_imx.c ├── configure.ac ├── microcom.1 ├── microcom.c ├── microcom.h ├── mux.c ├── parser.c ├── serial.c └── telnet.c /COPYING: -------------------------------------------------------------------------------- 1 | All files included in microcom are distributable under the "GNU GENERAL PUBLIC 2 | LICENSE version 2". (Some might have the "or any later version" phrase; this 3 | doesn't affect the previous statement though.) If the file doesn't specify a 4 | license explicitly, assume "version 2 only". The "GNU GENERAL PUBLIC LICENSE 5 | version 2" is appended below. 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | GNU GENERAL PUBLIC LICENSE 10 | Version 2, June 1991 11 | 12 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 13 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 14 | Everyone is permitted to copy and distribute verbatim copies 15 | of this license document, but changing it is not allowed. 16 | 17 | Preamble 18 | 19 | The licenses for most software are designed to take away your 20 | freedom to share and change it. By contrast, the GNU General Public 21 | License is intended to guarantee your freedom to share and change free 22 | software--to make sure the software is free for all its users. This 23 | General Public License applies to most of the Free Software 24 | Foundation's software and to any other program whose authors commit to 25 | using it. (Some other Free Software Foundation software is covered by 26 | the GNU Lesser General Public License instead.) You can apply it to 27 | your programs, too. 28 | 29 | When we speak of free software, we are referring to freedom, not 30 | price. Our General Public Licenses are designed to make sure that you 31 | have the freedom to distribute copies of free software (and charge for 32 | this service if you wish), that you receive source code or can get it 33 | if you want it, that you can change the software or use pieces of it 34 | in new free programs; and that you know you can do these things. 35 | 36 | To protect your rights, we need to make restrictions that forbid 37 | anyone to deny you these rights or to ask you to surrender the rights. 38 | These restrictions translate to certain responsibilities for you if you 39 | distribute copies of the software, or if you modify it. 40 | 41 | For example, if you distribute copies of such a program, whether 42 | gratis or for a fee, you must give the recipients all the rights that 43 | you have. You must make sure that they, too, receive or can get the 44 | source code. And you must show them these terms so they know their 45 | rights. 46 | 47 | We protect your rights with two steps: (1) copyright the software, and 48 | (2) offer you this license which gives you legal permission to copy, 49 | distribute and/or modify the software. 50 | 51 | Also, for each author's protection and ours, we want to make certain 52 | that everyone understands that there is no warranty for this free 53 | software. If the software is modified by someone else and passed on, we 54 | want its recipients to know that what they have is not the original, so 55 | that any problems introduced by others will not reflect on the original 56 | authors' reputations. 57 | 58 | Finally, any free program is threatened constantly by software 59 | patents. We wish to avoid the danger that redistributors of a free 60 | program will individually obtain patent licenses, in effect making the 61 | program proprietary. To prevent this, we have made it clear that any 62 | patent must be licensed for everyone's free use or not licensed at all. 63 | 64 | The precise terms and conditions for copying, distribution and 65 | modification follow. 66 | 67 | GNU GENERAL PUBLIC LICENSE 68 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 69 | 70 | 0. This License applies to any program or other work which contains 71 | a notice placed by the copyright holder saying it may be distributed 72 | under the terms of this General Public License. The "Program", below, 73 | refers to any such program or work, and a "work based on the Program" 74 | means either the Program or any derivative work under copyright law: 75 | that is to say, a work containing the Program or a portion of it, 76 | either verbatim or with modifications and/or translated into another 77 | language. (Hereinafter, translation is included without limitation in 78 | the term "modification".) Each licensee is addressed as "you". 79 | 80 | Activities other than copying, distribution and modification are not 81 | covered by this License; they are outside its scope. The act of 82 | running the Program is not restricted, and the output from the Program 83 | is covered only if its contents constitute a work based on the 84 | Program (independent of having been made by running the Program). 85 | Whether that is true depends on what the Program does. 86 | 87 | 1. You may copy and distribute verbatim copies of the Program's 88 | source code as you receive it, in any medium, provided that you 89 | conspicuously and appropriately publish on each copy an appropriate 90 | copyright notice and disclaimer of warranty; keep intact all the 91 | notices that refer to this License and to the absence of any warranty; 92 | and give any other recipients of the Program a copy of this License 93 | along with the Program. 94 | 95 | You may charge a fee for the physical act of transferring a copy, and 96 | you may at your option offer warranty protection in exchange for a fee. 97 | 98 | 2. You may modify your copy or copies of the Program or any portion 99 | of it, thus forming a work based on the Program, and copy and 100 | distribute such modifications or work under the terms of Section 1 101 | above, provided that you also meet all of these conditions: 102 | 103 | a) You must cause the modified files to carry prominent notices 104 | stating that you changed the files and the date of any change. 105 | 106 | b) You must cause any work that you distribute or publish, that in 107 | whole or in part contains or is derived from the Program or any 108 | part thereof, to be licensed as a whole at no charge to all third 109 | parties under the terms of this License. 110 | 111 | c) If the modified program normally reads commands interactively 112 | when run, you must cause it, when started running for such 113 | interactive use in the most ordinary way, to print or display an 114 | announcement including an appropriate copyright notice and a 115 | notice that there is no warranty (or else, saying that you provide 116 | a warranty) and that users may redistribute the program under 117 | these conditions, and telling the user how to view a copy of this 118 | License. (Exception: if the Program itself is interactive but 119 | does not normally print such an announcement, your work based on 120 | the Program is not required to print an announcement.) 121 | 122 | These requirements apply to the modified work as a whole. If 123 | identifiable sections of that work are not derived from the Program, 124 | and can be reasonably considered independent and separate works in 125 | themselves, then this License, and its terms, do not apply to those 126 | sections when you distribute them as separate works. But when you 127 | distribute the same sections as part of a whole which is a work based 128 | on the Program, the distribution of the whole must be on the terms of 129 | this License, whose permissions for other licensees extend to the 130 | entire whole, and thus to each and every part regardless of who wrote it. 131 | 132 | Thus, it is not the intent of this section to claim rights or contest 133 | your rights to work written entirely by you; rather, the intent is to 134 | exercise the right to control the distribution of derivative or 135 | collective works based on the Program. 136 | 137 | In addition, mere aggregation of another work not based on the Program 138 | with the Program (or with a work based on the Program) on a volume of 139 | a storage or distribution medium does not bring the other work under 140 | the scope of this License. 141 | 142 | 3. You may copy and distribute the Program (or a work based on it, 143 | under Section 2) in object code or executable form under the terms of 144 | Sections 1 and 2 above provided that you also do one of the following: 145 | 146 | a) Accompany it with the complete corresponding machine-readable 147 | source code, which must be distributed under the terms of Sections 148 | 1 and 2 above on a medium customarily used for software interchange; or, 149 | 150 | b) Accompany it with a written offer, valid for at least three 151 | years, to give any third party, for a charge no more than your 152 | cost of physically performing source distribution, a complete 153 | machine-readable copy of the corresponding source code, to be 154 | distributed under the terms of Sections 1 and 2 above on a medium 155 | customarily used for software interchange; or, 156 | 157 | c) Accompany it with the information you received as to the offer 158 | to distribute corresponding source code. (This alternative is 159 | allowed only for noncommercial distribution and only if you 160 | received the program in object code or executable form with such 161 | an offer, in accord with Subsection b above.) 162 | 163 | The source code for a work means the preferred form of the work for 164 | making modifications to it. For an executable work, complete source 165 | code means all the source code for all modules it contains, plus any 166 | associated interface definition files, plus the scripts used to 167 | control compilation and installation of the executable. However, as a 168 | special exception, the source code distributed need not include 169 | anything that is normally distributed (in either source or binary 170 | form) with the major components (compiler, kernel, and so on) of the 171 | operating system on which the executable runs, unless that component 172 | itself accompanies the executable. 173 | 174 | If distribution of executable or object code is made by offering 175 | access to copy from a designated place, then offering equivalent 176 | access to copy the source code from the same place counts as 177 | distribution of the source code, even though third parties are not 178 | compelled to copy the source along with the object code. 179 | 180 | 4. You may not copy, modify, sublicense, or distribute the Program 181 | except as expressly provided under this License. Any attempt 182 | otherwise to copy, modify, sublicense or distribute the Program is 183 | void, and will automatically terminate your rights under this License. 184 | However, parties who have received copies, or rights, from you under 185 | this License will not have their licenses terminated so long as such 186 | parties remain in full compliance. 187 | 188 | 5. You are not required to accept this License, since you have not 189 | signed it. However, nothing else grants you permission to modify or 190 | distribute the Program or its derivative works. These actions are 191 | prohibited by law if you do not accept this License. Therefore, by 192 | modifying or distributing the Program (or any work based on the 193 | Program), you indicate your acceptance of this License to do so, and 194 | all its terms and conditions for copying, distributing or modifying 195 | the Program or works based on it. 196 | 197 | 6. Each time you redistribute the Program (or any work based on the 198 | Program), the recipient automatically receives a license from the 199 | original licensor to copy, distribute or modify the Program subject to 200 | these terms and conditions. You may not impose any further 201 | restrictions on the recipients' exercise of the rights granted herein. 202 | You are not responsible for enforcing compliance by third parties to 203 | this License. 204 | 205 | 7. If, as a consequence of a court judgment or allegation of patent 206 | infringement or for any other reason (not limited to patent issues), 207 | conditions are imposed on you (whether by court order, agreement or 208 | otherwise) that contradict the conditions of this License, they do not 209 | excuse you from the conditions of this License. If you cannot 210 | distribute so as to satisfy simultaneously your obligations under this 211 | License and any other pertinent obligations, then as a consequence you 212 | may not distribute the Program at all. For example, if a patent 213 | license would not permit royalty-free redistribution of the Program by 214 | all those who receive copies directly or indirectly through you, then 215 | the only way you could satisfy both it and this License would be to 216 | refrain entirely from distribution of the Program. 217 | 218 | If any portion of this section is held invalid or unenforceable under 219 | any particular circumstance, the balance of the section is intended to 220 | apply and the section as a whole is intended to apply in other 221 | circumstances. 222 | 223 | It is not the purpose of this section to induce you to infringe any 224 | patents or other property right claims or to contest validity of any 225 | such claims; this section has the sole purpose of protecting the 226 | integrity of the free software distribution system, which is 227 | implemented by public license practices. Many people have made 228 | generous contributions to the wide range of software distributed 229 | through that system in reliance on consistent application of that 230 | system; it is up to the author/donor to decide if he or she is willing 231 | to distribute software through any other system and a licensee cannot 232 | impose that choice. 233 | 234 | This section is intended to make thoroughly clear what is believed to 235 | be a consequence of the rest of this License. 236 | 237 | 8. If the distribution and/or use of the Program is restricted in 238 | certain countries either by patents or by copyrighted interfaces, the 239 | original copyright holder who places the Program under this License 240 | may add an explicit geographical distribution limitation excluding 241 | those countries, so that distribution is permitted only in or among 242 | countries not thus excluded. In such case, this License incorporates 243 | the limitation as if written in the body of this License. 244 | 245 | 9. The Free Software Foundation may publish revised and/or new versions 246 | of the General Public License from time to time. Such new versions will 247 | be similar in spirit to the present version, but may differ in detail to 248 | address new problems or concerns. 249 | 250 | Each version is given a distinguishing version number. If the Program 251 | specifies a version number of this License which applies to it and "any 252 | later version", you have the option of following the terms and conditions 253 | either of that version or of any later version published by the Free 254 | Software Foundation. If the Program does not specify a version number of 255 | this License, you may choose any version ever published by the Free Software 256 | Foundation. 257 | 258 | 10. If you wish to incorporate parts of the Program into other free 259 | programs whose distribution conditions are different, write to the author 260 | to ask for permission. For software which is copyrighted by the Free 261 | Software Foundation, write to the Free Software Foundation; we sometimes 262 | make exceptions for this. Our decision will be guided by the two goals 263 | of preserving the free status of all derivatives of our free software and 264 | of promoting the sharing and reuse of software generally. 265 | 266 | NO WARRANTY 267 | 268 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 269 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 270 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 271 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 272 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 273 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 274 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 275 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 276 | REPAIR OR CORRECTION. 277 | 278 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 279 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 280 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 281 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 282 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 283 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 284 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 285 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 286 | POSSIBILITY OF SUCH DAMAGES. 287 | 288 | END OF TERMS AND CONDITIONS 289 | 290 | How to Apply These Terms to Your New Programs 291 | 292 | If you develop a new program, and you want it to be of the greatest 293 | possible use to the public, the best way to achieve this is to make it 294 | free software which everyone can redistribute and change under these terms. 295 | 296 | To do so, attach the following notices to the program. It is safest 297 | to attach them to the start of each source file to most effectively 298 | convey the exclusion of warranty; and each file should have at least 299 | the "copyright" line and a pointer to where the full notice is found. 300 | 301 | 302 | Copyright (C) 303 | 304 | This program is free software; you can redistribute it and/or modify 305 | it under the terms of the GNU General Public License as published by 306 | the Free Software Foundation; either version 2 of the License, or 307 | (at your option) any later version. 308 | 309 | This program is distributed in the hope that it will be useful, 310 | but WITHOUT ANY WARRANTY; without even the implied warranty of 311 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 312 | GNU General Public License for more details. 313 | 314 | You should have received a copy of the GNU General Public License along 315 | with this program; if not, write to the Free Software Foundation, Inc., 316 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 317 | 318 | Also add information on how to contact you by electronic and paper mail. 319 | 320 | If the program is interactive, make it output a short notice like this 321 | when it starts in an interactive mode: 322 | 323 | Gnomovision version 69, Copyright (C) year name of author 324 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 325 | This is free software, and you are welcome to redistribute it 326 | under certain conditions; type `show c' for details. 327 | 328 | The hypothetical commands `show w' and `show c' should show the appropriate 329 | parts of the General Public License. Of course, the commands you use may 330 | be called something other than `show w' and `show c'; they could even be 331 | mouse-clicks or menu items--whatever suits your program. 332 | 333 | You should also get your employer (if you work as a programmer) or your 334 | school, if any, to sign a "copyright disclaimer" for the program, if 335 | necessary. Here is a sample; alter the names: 336 | 337 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 338 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 339 | 340 | , 1 April 1989 341 | Ty Coon, President of Vice 342 | 343 | This General Public License does not permit incorporating your program into 344 | proprietary programs. If your program is a subroutine library, you may 345 | consider it more useful to permit linking proprietary applications with the 346 | library. If this is what you want to do, use the GNU Lesser General 347 | Public License instead of this License. 348 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | ACLOCAL_AMFLAGS = -I m4 --install 3 | 4 | EXTRA_DIST = DCO README.md 5 | 6 | bin_PROGRAMS = microcom 7 | microcom_SOURCES = commands.c commands_fsl_imx.c microcom.c mux.c parser.c serial.c telnet.c 8 | if CAN 9 | microcom_SOURCES += can.c 10 | endif 11 | 12 | dist_man1_MANS = microcom.1 13 | 14 | noinst_HEADERS = microcom.h 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | microcom 2 | ======== 3 | 4 | microcom is a minimalistic terminal program for communicating with devices over 5 | a serial connection (e.g. embedded systems, switches, modems). It features 6 | connection via RS232 serial interfaces (including setting of transfer rates) as 7 | well as in "Telnet mode" as specified in [RFC 2217]. 8 | 9 | [RFC 2217]: https://tools.ietf.org/html/rfc2217 10 | 11 | 12 | Installation 13 | ------------ 14 | 15 | microcom depends on the [readline] library. 16 | 17 | If you just cloned this repository, you also need to install [autoconf], 18 | [automake], and the [autoconf archive] first. Then change to the project's root 19 | directy and do: 20 | 21 | ``` 22 | autoreconf -i 23 | ``` 24 | 25 | If you extracted microcom from a release tarball, this previous step should not 26 | be needed. 27 | 28 | Now continue with building and installing microcom: 29 | 30 | ``` 31 | ./configure 32 | make 33 | sudo make install 34 | ``` 35 | 36 | By default, microcom is installed into `/usr/local/bin/`. Use `./configure 37 | --prefix=YOURPATH` to change that, and see `./configure --help` for more 38 | options related to building and installation. 39 | 40 | [readline]: https://tiswww.case.edu/php/chet/readline/rltop.html 41 | [autoconf]: https://www.gnu.org/software/autoconf/ 42 | [automake]: https://www.gnu.org/software/automake/ 43 | [autoconf archive]: https://www.gnu.org/software/autoconf-archive/ 44 | 45 | 46 | Usage 47 | ----- 48 | 49 | The typical usage with TTY devices looks like this: 50 | 51 | ``` 52 | microcom --speed=115200 --port=/dev/ttyS0 53 | ``` 54 | 55 | To connect to remote serial ports via RFC 2217, use the ``--telnet`` option instead: 56 | 57 | ``` 58 | microcom --speed=115200 --telnet=somehost:port 59 | ``` 60 | 61 | For the full list of options, see `microcom --help`. 62 | 63 | During the connection, you can get to the microcom menu by pressing `Ctrl-\`. 64 | Various options are available there, like setting flow control, RTS and DTR. 65 | See ``help`` for a full list. 66 | 67 | 68 | License and Contributing 69 | ------------------------ 70 | 71 | microcom is free software and distributable under the GNU General Public 72 | License, version 2. See the file `COPYING` in this repository for more 73 | information. 74 | 75 | Changes to microcom must be certified to be compatible with this license. For 76 | this purpose, we use the Developer's Certificate of Origin 1.1; see the file 77 | `DCO` in this repository. If you can certify that the DCO applies for your 78 | changes, add a line like the following: 79 | 80 | ``` 81 | Signed-off-by: Random J Developer 82 | ``` 83 | 84 | … containing your real name and e-mail address at the end of the patch 85 | description (Git can do this for you when you use `git commit -s`). 86 | Then send your patches to , or, if you use GitHub, 87 | open a pull-request on . 88 | If you send patches, please prefix your subject with "[PATCH microcom]" (for 89 | example, see the `git-config` manpage for the option `format.subjectPrefix`). 90 | -------------------------------------------------------------------------------- /can.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Description: the can part for microcom project 3 | * 4 | * Copyright (C) 2010 by Marc Kleine-Budde 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details at www.gnu.org 15 | * 16 | */ 17 | #include "config.h" 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include "microcom.h" 36 | 37 | struct can_data { 38 | int can_id; 39 | }; 40 | 41 | static struct can_data data; 42 | 43 | static ssize_t can_write(struct ios_ops *ios, const void *buf, size_t count) 44 | { 45 | size_t loopcount; 46 | ssize_t ret = 0, err; 47 | 48 | struct can_frame to_can = { 49 | .can_id = data.can_id, 50 | }; 51 | 52 | while (count > 0) { 53 | loopcount = min(count, sizeof(to_can.data)); 54 | memcpy(to_can.data, buf, loopcount); 55 | to_can.can_dlc = loopcount; 56 | retry: 57 | err = write(ios->fd, &to_can, sizeof(to_can)); 58 | if (err < 0 && errno == EINTR) 59 | goto retry; 60 | 61 | if (err < 0) 62 | return err; 63 | 64 | assert(err == sizeof(to_can)); 65 | buf += loopcount; 66 | count -= loopcount; 67 | ret += loopcount; 68 | } 69 | 70 | return ret; 71 | } 72 | 73 | static ssize_t can_read(struct ios_ops *ios, void *buf, size_t count) 74 | { 75 | struct can_frame from_can; 76 | ssize_t ret; 77 | 78 | retry: 79 | ret = read(ios->fd, &from_can, sizeof(from_can)); 80 | if (ret < 0 && errno != EINTR) 81 | goto retry; 82 | 83 | if (ret < 0) 84 | return ret; 85 | 86 | assert(count >= from_can.can_dlc); 87 | memcpy(buf, from_can.data, from_can.can_dlc); 88 | 89 | return from_can.can_dlc; 90 | } 91 | 92 | static int can_set_speed(struct ios_ops *ios, unsigned long speed) 93 | { 94 | return 0; 95 | } 96 | 97 | static int can_set_flow(struct ios_ops *ios, int flow) 98 | { 99 | return 0; 100 | } 101 | 102 | static int can_send_break(struct ios_ops *ios) 103 | { 104 | return 0; 105 | } 106 | 107 | static void can_exit(struct ios_ops *ios) 108 | { 109 | close(ios->fd); 110 | free(ios); 111 | } 112 | 113 | struct ios_ops *can_init(char *interface_id) 114 | { 115 | struct ios_ops *ios; 116 | struct ifreq ifr; 117 | struct can_filter filter[] = { 118 | { 119 | .can_mask = CAN_SFF_MASK, 120 | }, 121 | }; 122 | struct sockaddr_can addr = { 123 | .can_family = PF_CAN, 124 | }; 125 | char *interface = interface_id; 126 | char *id_str = NULL; 127 | 128 | ios = malloc(sizeof(*ios)); 129 | if (!ios) 130 | return NULL; 131 | 132 | ios->write = can_write; 133 | ios->read = can_read; 134 | ios->set_speed = can_set_speed; 135 | ios->set_flow = can_set_flow; 136 | ios->send_break = can_send_break; 137 | ios->exit = can_exit; 138 | 139 | /* 140 | * the string is supposed to be formated this way: 141 | * interface:rx:tx 142 | */ 143 | if (interface_id) 144 | id_str = strchr(interface, ':'); 145 | 146 | if (id_str) { 147 | *id_str = 0x0; 148 | id_str++; 149 | filter->can_id = strtol(id_str, NULL, 16) & CAN_SFF_MASK; 150 | 151 | id_str = strchr(id_str, ':'); 152 | } else { 153 | filter->can_id = DEFAULT_CAN_ID; 154 | } 155 | 156 | if (id_str) { 157 | *id_str = 0x0; 158 | id_str++; 159 | data.can_id = strtol(id_str, NULL, 16) & CAN_SFF_MASK; 160 | } else { 161 | data.can_id = filter->can_id; 162 | } 163 | 164 | if (!interface || *interface == 0x0) 165 | interface = DEFAULT_CAN_INTERFACE; 166 | 167 | /* no cleanups on failure, we exit anyway */ 168 | 169 | ios->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); 170 | if (ios->fd < 0) { 171 | perror("socket"); 172 | return NULL; 173 | } 174 | 175 | if (setsockopt(ios->fd, SOL_CAN_RAW, CAN_RAW_FILTER, 176 | filter, sizeof(filter))) { 177 | perror("setsockopt"); 178 | return NULL; 179 | } 180 | 181 | strcpy(ifr.ifr_name, interface); 182 | if (ioctl(ios->fd, SIOCGIFINDEX, &ifr)) { 183 | printf("%s: %s\n", interface, strerror(errno)); 184 | return NULL; 185 | } 186 | addr.can_ifindex = ifr.ifr_ifindex; 187 | 188 | if (bind(ios->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { 189 | perror("bind"); 190 | return NULL; 191 | } 192 | 193 | printf("connected to %s (rx_id=%x, tx_id=%x)\n", 194 | interface, filter->can_id, data.can_id); 195 | 196 | return ios; 197 | } 198 | -------------------------------------------------------------------------------- /commands.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Sascha Hauer 3 | * 4 | * This program is free software; you can redistribute it and/or modify it under 5 | * the terms of the GNU General Public License as published by the Free Software 6 | * Foundation; either version 2 of the License, or (at your option) any later 7 | * version. 8 | */ 9 | #include "config.h" 10 | 11 | #include 12 | #include "microcom.h" 13 | 14 | static int cmd_speed(int argc, char *argv[]) 15 | { 16 | unsigned long speed; 17 | int ret; 18 | 19 | if (argc < 2) { 20 | printf("current speed: %lu\n", current_speed); 21 | return 0; 22 | } 23 | 24 | speed = strtoul(argv[1], NULL, 0); 25 | 26 | ret = ios->set_speed(ios, speed); 27 | if (ret) { 28 | fprintf(stderr, "invalid speed %lu\n", speed); 29 | return ret; 30 | } 31 | 32 | current_speed = speed; 33 | return 0; 34 | } 35 | 36 | static int cmd_flow(int argc, char *argv[]) 37 | { 38 | char *flow; 39 | 40 | if (argc < 2) { 41 | switch (current_flow) { 42 | default: 43 | case FLOW_NONE: 44 | flow = "none"; 45 | break; 46 | case FLOW_SOFT: 47 | flow = "soft"; 48 | break; 49 | case FLOW_HARD: 50 | flow = "hard"; 51 | break; 52 | } 53 | printf("current flow: %s\n", flow); 54 | return 0; 55 | } 56 | 57 | switch (*argv[1]) { 58 | case 'n': 59 | current_flow = FLOW_NONE; 60 | break; 61 | case 's': 62 | current_flow = FLOW_SOFT; 63 | break; 64 | case 'h': 65 | current_flow = FLOW_HARD; 66 | break; 67 | default: 68 | printf("unknown flow type \"%s\"\n", argv[1]); 69 | return 1; 70 | } 71 | 72 | ios->set_flow(ios, current_flow); 73 | 74 | return 0; 75 | } 76 | 77 | static int current_dtr = 0; 78 | static int current_rts = 0; 79 | 80 | static int cmd_set_handshake_line(int argc, char *argv[]) 81 | { 82 | int enable; 83 | int ret = 0; 84 | int pin = 0; 85 | 86 | if (!ios->set_handshake_line) { 87 | printf("function not supported \"%s\"\n", argv[0]); 88 | return 1; 89 | } 90 | 91 | if (!strncmp(argv[0], "dtr", 3)) 92 | pin = PIN_DTR; 93 | else if (!strncmp(argv[0], "rts", 3)) 94 | pin = PIN_RTS; 95 | 96 | if (!pin) { 97 | printf("unknown pin \"%s\"\n", argv[0]); 98 | return 1; 99 | } 100 | 101 | if (argc < 2) { 102 | switch (pin) { 103 | case PIN_DTR: 104 | printf("current dtr: \"%d\"\n", current_dtr); 105 | break; 106 | case PIN_RTS: 107 | printf("current rts: \"%d\"\n", current_rts); 108 | break; 109 | } 110 | return 0; 111 | } 112 | 113 | if (!strncmp(argv[1], "1", strlen(argv[1]))) { 114 | enable = 1; 115 | } else if (!strncmp(argv[1], "0", strlen(argv[1]))) { 116 | enable = 0; 117 | } else { 118 | printf("unknown dtr state \"%s\"\n", argv[1]); 119 | return 1; 120 | } 121 | 122 | printf("setting %s: \"%d\"\n", argv[0], enable); 123 | ret = ios->set_handshake_line(ios, pin, enable); 124 | if (ret) 125 | return ret; 126 | 127 | switch (pin) { 128 | case PIN_DTR: 129 | current_dtr = enable; 130 | break; 131 | case PIN_RTS: 132 | current_rts = enable; 133 | break; 134 | } 135 | 136 | return 0; 137 | } 138 | 139 | static int cmd_exit(int argc, char *argv[]) 140 | { 141 | return MICROCOM_CMD_START; 142 | } 143 | 144 | static int cmd_break(int argc, char *argv[]) 145 | { 146 | ios->send_break(ios); 147 | return MICROCOM_CMD_START; 148 | } 149 | 150 | static int cmd_quit(int argc, char *argv[]) 151 | { 152 | microcom_exit(0); 153 | return 0; 154 | } 155 | 156 | static int cmd_sendescape(int argc, char *argv[]) 157 | { 158 | ios->write(ios, "\x1c", 1); 159 | return 0; 160 | } 161 | 162 | static int cmd_help(int argc, char *argv[]) 163 | { 164 | struct cmd *cmd; 165 | 166 | if (argc == 1) { 167 | for_each_command(cmd) { 168 | if (cmd->info) 169 | printf("%s - %s\n", cmd->name, cmd->info); 170 | else 171 | printf("%s\n", cmd->name); 172 | } 173 | } else { 174 | microcom_cmd_usage(argv[1]); 175 | } 176 | 177 | return 0; 178 | } 179 | 180 | static int cmd_execute(int argc, char *argv[]) 181 | { 182 | if (argc < 2) 183 | return MICROCOM_CMD_USAGE; 184 | 185 | return do_script(argv[1]); 186 | } 187 | 188 | static int cmd_log(int argc, char *argv[]) 189 | { 190 | int ret; 191 | 192 | if (argc < 2) 193 | return MICROCOM_CMD_USAGE; 194 | 195 | ret = logfile_open(argv[1]); 196 | 197 | return ret; 198 | } 199 | 200 | static int cmd_comment(int argc, char *argv[]) 201 | { 202 | return 0; 203 | } 204 | 205 | static struct cmd cmds[] = { 206 | { 207 | .name = "speed", 208 | .fn = cmd_speed, 209 | .info = "set terminal speed", 210 | .help = "speed " 211 | }, { 212 | .name = "exit", 213 | .fn = cmd_exit, 214 | .info = "exit from command processing", 215 | }, { 216 | .name = "flow", 217 | .fn = cmd_flow, 218 | .info = "set flow control", 219 | .help = "flow hard|soft|none", 220 | }, { 221 | .name = "dtr", 222 | .fn = cmd_set_handshake_line, 223 | .info = "set dtr value", 224 | .help = "dtr 1|0", 225 | }, { 226 | .name = "rts", 227 | .fn = cmd_set_handshake_line, 228 | .info = "set rts value", 229 | .help = "rts 1|0", 230 | }, { 231 | .name = "break", 232 | .fn = cmd_break, 233 | .info = "send break", 234 | }, { 235 | .name = "sendescape", 236 | .fn = cmd_sendescape, 237 | .info = "send a Ctrl-\\", 238 | }, { 239 | .name = "quit", 240 | .fn = cmd_quit, 241 | .info = "quit microcom", 242 | }, { 243 | .name = "help", 244 | .fn = cmd_help, 245 | .info = "show help", 246 | }, { 247 | .name = "x", 248 | .fn = cmd_execute, 249 | .info = "execute a script", 250 | .help = "x ", 251 | }, { 252 | .name = "log", 253 | .fn = cmd_log, 254 | .info = "log to file", 255 | .help = "log ", 256 | }, { 257 | .name = "#", 258 | .fn = cmd_comment, 259 | .info = "comment", 260 | }, 261 | }; 262 | 263 | void commands_init(void) 264 | { 265 | int i; 266 | 267 | for (i = 0; i < ARRAY_SIZE(cmds); i++) 268 | register_command(&cmds[i]); 269 | } 270 | -------------------------------------------------------------------------------- /commands_fsl_imx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Sascha Hauer 3 | * 4 | * This program is free software; you can redistribute it and/or modify it under 5 | * the terms of the GNU General Public License as published by the Free Software 6 | * Foundation; either version 2 of the License, or (at your option) any later 7 | * version. 8 | */ 9 | #include "config.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "microcom.h" 16 | 17 | static int available(int fd) 18 | { 19 | fd_set rfds; 20 | struct timeval tv = { 21 | .tv_sec = 0, 22 | .tv_usec = 1 23 | }; 24 | int ret; 25 | 26 | /* Watch stdin (fd 0) to see when it has input. */ 27 | FD_ZERO(&rfds); 28 | FD_SET(fd, &rfds); 29 | ret = select(fd + 1, &rfds, NULL, NULL, &tv); 30 | if (ret == -1) { 31 | perror("select"); 32 | return -EINVAL; 33 | } 34 | 35 | if (ret) 36 | return 1; 37 | else 38 | return 0; 39 | } 40 | 41 | static int get_ack(int fd) 42 | { 43 | unsigned char expect[] = { 0x56, 0x78, 0x78, 0x56 }; 44 | int i, ret; 45 | unsigned char r; 46 | 47 | for (i = 0; i < sizeof(expect); i++) { 48 | ret = read(ios->fd, &r, 1); 49 | if (ret == -1) { 50 | perror("read failed\n"); 51 | return -1; 52 | } 53 | if (r != expect[i]) 54 | return -1;; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | static int sync_com(int fd) 61 | { 62 | unsigned char buf = 0x1; 63 | int ret, i; 64 | 65 | for (i = 0; i < 16; i++) { 66 | while (1) { 67 | printf("wr %d\n", i++); 68 | ret = write(ios->fd, &buf, 1); 69 | if (ret < 0) 70 | perror("write"); 71 | usleep(100000); 72 | if (available(fd)) 73 | break; 74 | } 75 | ret = get_ack(fd); 76 | if (!ret) 77 | return ret; 78 | printf("no ack. try again\n"); 79 | } 80 | 81 | printf("failed to connect\n"); 82 | 83 | return -EINVAL; 84 | } 85 | 86 | static int read_mem(int fd, uint32_t address, void *_buf, int size, int accesssize) 87 | { 88 | unsigned char buf[] = {0x1, 0x1, /* read command */ 89 | 0x0, 0x0, 0x0, 0x0, /* address */ 90 | 0x20, /* data size */ 91 | 0x0, 0x0, 0x0, 0x0, /* count */ 92 | 0x0, 0x0, 0x0, 0x0, 0x0}; /* fill */ 93 | int i = 0, ret; 94 | uint8_t *buf8 = _buf; 95 | uint16_t *buf16 = _buf; 96 | uint32_t *buf32 = _buf; 97 | 98 | buf[2] = (address >> 24) & 0xff; 99 | buf[3] = (address >> 16) & 0xff; 100 | buf[4] = (address >> 8) & 0xff; 101 | buf[5] = (address >> 0) & 0xff; 102 | 103 | switch (accesssize) { 104 | case 8: 105 | case 16: 106 | case 32: 107 | buf[6] = accesssize; 108 | break; 109 | default: 110 | return -EINVAL; 111 | } 112 | 113 | size -= 1; 114 | 115 | buf[7] = (size >> 24) & 0xff; 116 | buf[8] = (size >> 16) & 0xff; 117 | buf[9] = (size >> 8) & 0xff; 118 | buf[10] = (size >> 0) & 0xff; 119 | 120 | for (i = 0; i < sizeof(buf); i++) { 121 | ret = write(ios->fd, &buf[i], 1); 122 | if (ret < 0) { 123 | perror("write"); 124 | return -EINVAL; 125 | } 126 | } 127 | 128 | usleep(100000); 129 | 130 | ret = get_ack(fd); 131 | if (ret) 132 | return ret; 133 | 134 | i = 0; 135 | 136 | while (i < size) { 137 | uint8_t temp; 138 | 139 | switch (accesssize) { 140 | case 8: 141 | ret = read(fd, buf8, 1); 142 | if (ret < 0) 143 | return -EINVAL; 144 | buf8++; 145 | i++; 146 | break; 147 | case 16: 148 | ret = read(fd, &temp, 1); 149 | if (ret < 0) 150 | return -EINVAL; 151 | *buf16 = temp; 152 | ret = read(fd, &temp, 1); 153 | if (ret < 0) 154 | return -EINVAL; 155 | *buf16 |= temp << 8; 156 | buf16++; 157 | i += 2; 158 | break; 159 | case 32: 160 | ret = read(fd, &temp, 1); 161 | if (ret < 0) 162 | return -EINVAL; 163 | *buf32 = temp; 164 | ret = read(fd, &temp, 1); 165 | if (ret < 0) 166 | return -EINVAL; 167 | *buf32 |= temp << 8; 168 | ret = read(fd, &temp, 1); 169 | if (ret < 0) 170 | return -EINVAL; 171 | *buf32 |= temp << 16; 172 | ret = read(fd, &temp, 1); 173 | if (ret < 0) 174 | return -EINVAL; 175 | *buf32 |= temp << 24; 176 | buf32++; 177 | i += 4; 178 | break; 179 | } 180 | } 181 | return 0; 182 | } 183 | 184 | #define DISP_LINE_LEN 16 185 | 186 | static int memory_display(char *addr, unsigned long offs, unsigned long nbytes, int size) 187 | { 188 | unsigned long linebytes, i; 189 | unsigned char *cp; 190 | 191 | /* Print the lines. 192 | * 193 | * We buffer all read data, so we can make sure data is read only 194 | * once, and all accesses are with the specified bus width. 195 | */ 196 | do { 197 | char linebuf[DISP_LINE_LEN]; 198 | uint *uip = (uint *)linebuf; 199 | ushort *usp = (ushort *)linebuf; 200 | u_char *ucp = (u_char *)linebuf; 201 | uint count = 52; 202 | 203 | printf("%08lx:", offs); 204 | linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes; 205 | 206 | for (i = 0; i < linebytes; i += size) { 207 | if (size == 4) { 208 | count -= printf(" %08x", (*uip++ = *((uint *)addr))); 209 | } else if (size == 2) { 210 | count -= printf(" %04x", (*usp++ = *((ushort *)addr))); 211 | } else { 212 | count -= printf(" %02x", (*ucp++ = *((u_char *)addr))); 213 | } 214 | addr += size; 215 | offs += size; 216 | } 217 | 218 | while(count--) 219 | printf(" "); 220 | 221 | cp = (unsigned char *)linebuf; 222 | for (i = 0; i < linebytes; i++) { 223 | if ((*cp < 0x20) || (*cp > 0x7e)) 224 | printf("."); 225 | else 226 | printf("%c", *cp); 227 | cp++; 228 | } 229 | printf("\n"); 230 | nbytes -= linebytes; 231 | } while (nbytes > 0); 232 | 233 | return 0; 234 | } 235 | 236 | static int md(int argc, char *argv[]) 237 | { 238 | void *buf; 239 | uint32_t addr; 240 | int accesssize = 32; 241 | int size = 256; 242 | int ret = 0; 243 | 244 | if (argc < 2) 245 | return 1; 246 | 247 | addr = strtoul(argv[1], NULL, 0); 248 | 249 | buf = malloc(size); 250 | 251 | ret = read_mem(ios->fd, addr, buf, size, accesssize); 252 | if (ret) 253 | goto out; 254 | 255 | memory_display(buf, 0x0, size, accesssize >> 3); 256 | out: 257 | free(buf); 258 | 259 | return ret; 260 | } 261 | 262 | static int write_mem(uint32_t address, uint32_t val, int accesssize) 263 | { 264 | unsigned char buf[] = { 0x2, 0x2, /* write command */ 265 | 0x0, 0x0, 0x0, 0x0, /* address */ 266 | 0x0, /* data size */ 267 | 0x0, 0x0, 0x0, 0x0, /* fill */ 268 | 0x0, 0x0, 0x0, 0x0, /* value */ 269 | 0x0, /* fill */ 270 | }; 271 | unsigned char expect[] = {0x12, 0x8a, 0x8a, 0x12}; 272 | int i, ret; 273 | unsigned char r; 274 | 275 | buf[2] = (address >> 24) & 0xff; 276 | buf[3] = (address >> 16) & 0xff; 277 | buf[4] = (address >> 8) & 0xff; 278 | buf[5] = (address >> 0) & 0xff; 279 | 280 | switch (accesssize) { 281 | case 8: 282 | buf[11] = val & 0xff; 283 | buf[6] = accesssize; 284 | break; 285 | case 16: 286 | buf[11] = (val >> 8) & 0xff; 287 | buf[12] = val & 0xff; 288 | buf[6] = accesssize; 289 | break; 290 | case 32: 291 | buf[11] = (val >> 24) & 0xff; 292 | buf[12] = (val >> 16) & 0xff; 293 | buf[13] = (val >> 8) & 0xff; 294 | buf[14] = (val >> 0) & 0xff; 295 | buf[6] = accesssize; 296 | break; 297 | default: 298 | return -EINVAL; 299 | } 300 | 301 | for (i = 0; i < ARRAY_SIZE(buf); i++) { 302 | ret = write(ios->fd, &buf[i], 1); 303 | if (ret < 0) { 304 | perror("write"); 305 | return -EINVAL; 306 | } 307 | } 308 | 309 | ret = get_ack(ios->fd); 310 | if (ret) 311 | return ret; 312 | 313 | for (i = 0; i < sizeof(expect); i++) { 314 | ret = read(ios->fd, &r, 1); 315 | if (ret == -1) { 316 | perror("read failed\n"); 317 | return -1; 318 | } 319 | if (r != expect[i]) 320 | return -1;; 321 | } 322 | 323 | return 0; 324 | } 325 | 326 | static int mw(int argc, char *argv[]) 327 | { 328 | uint32_t addr, val; 329 | int accesssize = 32; 330 | 331 | if (argc < 3) 332 | return 1; 333 | 334 | if (!strcmp(argv[0], "mwb")) 335 | accesssize = 8; 336 | if (!strcmp(argv[0], "mwh")) 337 | accesssize = 16; 338 | 339 | addr = strtoul(argv[1], NULL, 0); 340 | val = strtoul(argv[2], NULL, 0); 341 | 342 | write_mem(addr, val, accesssize); 343 | 344 | return 0; 345 | } 346 | 347 | static int do_header(uint32_t addr) 348 | { 349 | int i, ret; 350 | unsigned char buf[] = { 351 | 0x20, 0x0, 0x0, 0x80, 352 | 0x0, 0x0, 0x0, 0x0, 353 | 0x0, 0x0, 0x0, 0x0, 354 | 0x0, 0x0, 0x0, 0x0, 355 | 0x0, 0x0, 0x0, 0x0, 356 | 0x0, 0x0, 0x0, 0x0, 357 | 0x0, 0x0, 0x0, 0x0, 358 | 0x0, 0x0, 0x0, 0x0, 359 | }; 360 | buf[0] = (addr >> 0) & 0xff; 361 | buf[1] = (addr >> 8) & 0xff; 362 | buf[2] = (addr >> 16) & 0xff; 363 | buf[3] = (addr >> 24) & 0xff; 364 | 365 | for (i = 0; i < ARRAY_SIZE(buf); i++) { 366 | ret = write(ios->fd, &buf[i], 1); 367 | if (ret < 0) { 368 | perror("write"); 369 | return -EINVAL; 370 | } 371 | } 372 | 373 | return 0; 374 | } 375 | 376 | static int upload_file(uint32_t address, char *name, unsigned char type) 377 | { 378 | uint32_t size; 379 | int upfd, ret, i; 380 | unsigned char buf[] = { 0x4, 0x4, /* upload command */ 381 | 0x0, 0x0, 0x0, 0x0, /* address */ 382 | 0x0, /* fill */ 383 | 0x0, 0x0, 0x0, 0x0, /* filesize */ 384 | 0x0, 0x0, 0x0, 0x0, /* fill */ 385 | 0xaa, /* filetype */ 386 | }; 387 | struct stat stat; 388 | 389 | upfd = open(name, O_RDONLY); 390 | if (upfd < 0) { 391 | perror("open"); 392 | return 1; 393 | } 394 | 395 | ret = fstat(upfd, &stat); 396 | if (ret) { 397 | perror("stat"); 398 | return 1; 399 | } 400 | 401 | size = stat.st_size; 402 | size += 0x20; 403 | 404 | buf[2] = (address >> 24) & 0xff; 405 | buf[3] = (address >> 16) & 0xff; 406 | buf[4] = (address >> 8) & 0xff; 407 | buf[5] = (address >> 0) & 0xff; 408 | 409 | buf[7] = (size >> 24) & 0xff; 410 | buf[8] = (size >> 16) & 0xff; 411 | buf[9] = (size >> 8) & 0xff; 412 | buf[10] = (size >> 0) & 0xff; 413 | 414 | for (i = 11; i < 16; i++) 415 | buf[i] = type; 416 | 417 | for (i = 0; i < ARRAY_SIZE(buf); i++) { 418 | ret = write(ios->fd, &buf[i], 1); 419 | if (ret < 0) { 420 | perror("write"); 421 | return -EINVAL; 422 | } 423 | } 424 | 425 | ret = get_ack(ios->fd); 426 | if (ret) { 427 | printf("no ack\n"); 428 | return ret; 429 | } 430 | 431 | do_header(address + 0x20); 432 | 433 | for (i = 0; i < size - 0x20; i++) { 434 | unsigned char tmp; 435 | ret = read(upfd, &tmp, 1); 436 | if (ret != 1) { 437 | perror("read"); 438 | goto out; 439 | } 440 | ret = write(ios->fd, &tmp, 1); 441 | if (ret != 1) { 442 | perror("write"); 443 | goto out; 444 | } 445 | if (!(i % 65536)) 446 | printf("\n "); 447 | if (!((i + 1) % 1024)) 448 | printf("#"); 449 | fflush(stdout); 450 | } 451 | 452 | printf("\n"); 453 | 454 | out: 455 | return 0; 456 | } 457 | 458 | static int upload(int argc, char *argv[]) 459 | { 460 | uint32_t address; 461 | unsigned char buf[] = { 0x5, 0x5, /* status command */ 462 | 0x0, 0x0, 0x0, 0x0, 463 | 0x0, 0x0, 0x0, 0x0, 464 | 0x0, 0x0, 0x0, 0x0, 465 | 0x0, 0x0, 466 | }; 467 | int i, ret, type = 0; 468 | 469 | if (argc < 3) 470 | return 1; 471 | 472 | if (argc > 3) { 473 | type = strtoul(argv[3], NULL, 0); 474 | printf("image type: 0x%02x\n", type); 475 | } 476 | 477 | address = strtoul(argv[1], NULL, 0); 478 | upload_file(address, argv[2], type); 479 | 480 | for (i = 0; i < ARRAY_SIZE(buf); i++) { 481 | ret = write(ios->fd, &buf[i], 1); 482 | if (ret < 0) { 483 | perror("write"); 484 | return -EINVAL; 485 | } 486 | } 487 | 488 | if (type == 0xaa) 489 | return MICROCOM_CMD_START; 490 | 491 | return 0; 492 | } 493 | 494 | static int fsl_connect(int argc, char *argv[]) 495 | { 496 | int ret; 497 | 498 | printf("trying to connect...\n"); 499 | ret = sync_com(ios->fd); 500 | if (ret) { 501 | printf("connect failed\n"); 502 | return -11; 503 | } 504 | printf("done\n"); 505 | return 0; 506 | } 507 | 508 | static void fsl_sniff_memwrite(void) 509 | { 510 | unsigned char buf[15]; 511 | int i; 512 | uint32_t addr, val; 513 | 514 | printf("mw "); 515 | for (i = 0; i < 15; i++) { 516 | read(ios->fd, &buf[i], 1); 517 | } 518 | 519 | addr = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0); 520 | val = (buf[10] << 24)| (buf[11] << 16) | (buf[12] << 8) | (buf[13] << 0); 521 | printf("0x%08x 0x%08x\n", addr, val); 522 | } 523 | 524 | static void fsl_sniff_6(void) 525 | { 526 | unsigned char buf[15]; 527 | int i; 528 | 529 | printf("cmd6\n"); 530 | for (i = 0; i < 15; i++) { 531 | read(ios->fd, &buf[i], 1); 532 | printf("%02x ", buf[i]); 533 | } 534 | printf("\n"); 535 | } 536 | 537 | static void fsl_sniff_sts(void) 538 | { 539 | unsigned char buf[15]; 540 | int i; 541 | 542 | printf("cmd get status\n"); 543 | for (i = 0; i < 15; i++) { 544 | read(ios->fd, &buf[i], 1); 545 | printf("%02x ", buf[i]); 546 | } 547 | printf("\n"); 548 | } 549 | 550 | static void fsl_sniff_memread(void) 551 | { 552 | printf("md (not implemented)\n"); 553 | } 554 | 555 | static void fsl_sniff_upload(void) 556 | { 557 | unsigned char buf[15]; 558 | uint32_t addr, size; 559 | int i; 560 | 561 | printf("upload "); 562 | 563 | for (i = 0; i < 15; i++) { 564 | read(ios->fd, &buf[i], 1); 565 | } 566 | addr = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | (buf[4] << 0); 567 | size = (buf[6] << 24) | (buf[7] << 16) | (buf[8] << 8) | (buf[9] << 0); 568 | 569 | printf(" adr: 0x%08x size: 0x%08x type 0x%02x ", addr, size, buf[14]); 570 | 571 | switch(buf[14]) { 572 | case 0xaa: 573 | printf("(application)\n"); 574 | break; 575 | case 0xee: 576 | printf("(dcd)\n"); 577 | break; 578 | default: 579 | printf("(unknown)\n"); 580 | break; 581 | } 582 | 583 | for (i = 0; i < size; i++) { 584 | unsigned char tmp; 585 | read(ios->fd, &tmp, 1); 586 | printf("%02x ", tmp); 587 | if (!((i + 1) % 32)) 588 | printf("\n"); 589 | } 590 | printf("\n"); 591 | } 592 | 593 | static int fsl_sniff(int argc, char *argv[]) 594 | { 595 | while (1) { 596 | unsigned char cmd; 597 | read(ios->fd, &cmd, 1); 598 | switch (cmd) { 599 | case 0x2: 600 | fsl_sniff_memwrite(); 601 | break; 602 | case 0x1: 603 | fsl_sniff_memread(); 604 | break; 605 | case 0x4: 606 | fsl_sniff_upload(); 607 | break; 608 | case 0x5: 609 | fsl_sniff_sts(); 610 | break; 611 | case 0x6: 612 | fsl_sniff_6(); 613 | break; 614 | default: 615 | printf("unknown cmd 0x%02x\n", cmd); 616 | break; 617 | }; 618 | } 619 | 620 | return 0; 621 | } 622 | 623 | static struct cmd cmds[] = { 624 | { 625 | .name = "md", 626 | .fn = md, 627 | .info = "Display memory (i.MX specific)", 628 | .help = "md
", 629 | }, { 630 | .name = "mw", 631 | .fn = mw, 632 | .info = "write memory (i.MX specific)", 633 | .help = "mw
", 634 | }, { 635 | .name = "mwb", 636 | .fn = mw, 637 | .info = "write memory byte (i.MX specific)", 638 | .help = "mwb
", 639 | }, { 640 | .name = "mwh", 641 | .fn = mw, 642 | .info = "write memory 2 byte (i.MX specific)", 643 | .help = "mwh
", 644 | }, { 645 | .name = "upload", 646 | .fn = upload, 647 | .info = "upload image (i.MX specific)", 648 | .help = "upload
[]\n" 649 | "use imagetype = 0xaa for application images", 650 | }, { 651 | .name = "connect", 652 | .fn = fsl_connect, 653 | .info = "sync communication to Processor (i.MX specific)", 654 | .help = "connect", 655 | }, { 656 | .name = "sniff", 657 | .fn = fsl_sniff, 658 | .info = "sniff and dissect communication from ATK (i.MX specific)", 659 | .help = "sniff", 660 | }, 661 | }; 662 | 663 | void commands_fsl_imx_init(void) 664 | { 665 | int i; 666 | 667 | for (i = 0; i < ARRAY_SIZE(cmds); i++) 668 | register_command(&cmds[i]); 669 | } 670 | 671 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([microcom], [2023.09.0], [oss-tools@pengutronix.de]) 2 | AC_CONFIG_AUX_DIR([build-aux]) 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | AM_INIT_AUTOMAKE([dist-xz]) 5 | 6 | AC_PREREQ([2.69]) 7 | AC_CONFIG_SRCDIR([commands_fsl_imx.c]) 8 | AC_CONFIG_HEADERS([config.h]) 9 | 10 | # Checks for programs. 11 | AC_PROG_CC 12 | AC_SYS_LARGEFILE 13 | 14 | # Checks for libraries. 15 | AC_SEARCH_LIBS([readline], [readline],,[AC_MSG_ERROR([Please install readline development files (libreadline-dev)])]) 16 | 17 | # Checks for header files. 18 | AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/file.h sys/ioctl.h sys/socket.h sys/time.h termios.h unistd.h]) 19 | AC_CHECK_HEADER_STDBOOL 20 | 21 | # Checks for typedefs, structures, and compiler characteristics. 22 | AC_TYPE_SIZE_T 23 | AC_TYPE_UINT16_T 24 | AC_TYPE_UINT32_T 25 | AC_TYPE_UINT8_T 26 | AC_TYPE_SSIZE_T 27 | 28 | # Checks for library functions. 29 | AC_FUNC_MALLOC 30 | AC_CHECK_FUNCS([dup2 memset select socket strchr strerror strrchr strtol strtoul]) 31 | 32 | AC_ARG_ENABLE([can], [AS_HELP_STRING([--enable-can], [enable can mode @<:@default=check@:>@])],, 33 | [enable_can=check]) 34 | 35 | AS_IF([test "x$enable_can" != "xno"], 36 | [AC_CHECK_HEADERS([linux/can.h linux/can/raw.h],, 37 | [AS_IF([test "x$enable_can" != "xyes"], [enable_can=no; break], [AC_MSG_ERROR([can depends on Linux can headers])])]) 38 | AS_IF([test "x$enable_can" = "xcheck"], [enable_can=yes]) 39 | ]) 40 | 41 | AS_IF([test "x$enable_can" = "xyes"], 42 | [AC_DEFINE([USE_CAN], [1], [Define if can mode should be built-in])]) 43 | 44 | AM_CONDITIONAL([CAN], [test "x$enable_can" = "xyes"]) 45 | 46 | AC_CONFIG_FILES([Makefile]) 47 | 48 | AC_OUTPUT 49 | -------------------------------------------------------------------------------- /microcom.1: -------------------------------------------------------------------------------- 1 | '\" 2 | '\" Copyright (C) 2009 Alexander Reichle-Schmehl 3 | '\" Copyright (C) 2013 Uwe Kleine-König 4 | .TH "MICROCOM" "1" 5 | .SH "NAME" 6 | microcom \- A minimalistic terminal program 7 | .SH "SYNOPSIS" 8 | .PP 9 | .B microcom 10 | .RB [ -d ] 11 | .RB [ -f ] 12 | .RB [\| \-p 13 | .IR devfile |\| \fB\-t 14 | .IR host : port ] 15 | .RB [\| \-s 16 | .IR speed \|] 17 | .br 18 | .B microcom -c 19 | .IB interface : rx_id : tx_id 20 | .br 21 | .B microcom -h 22 | 23 | .SH "DESCRIPTION" 24 | .PP 25 | This manual page documents briefly the 26 | \fBmicrocom\fR command. 27 | .PP 28 | \fBmicrocom\fR is a is a minimalistic terminal 29 | program for accessing devices (e.g. switches) via a serial connection. 30 | It features connection via RS232 serial interfaces (including setting of 31 | transferrates) as well as in `telnetmode' as specified in 32 | rfc2217 and a (Linux specific) can mode. 33 | .PP 34 | The escape character to enter the program menu is crtl-\e. There are several 35 | commands available, among them 36 | .B quit 37 | (to exit microcom), 38 | .B exit 39 | (to return to normal mode) and 40 | .B speed 41 | (to set terminal speed) 42 | 43 | .SH "OPTIONS" 44 | .PP 45 | .B microcom 46 | follows the usual GNU command line syntax, with long options starting with two 47 | dashes (`\-'). A summary of options is included below. 48 | .TP 49 | .B \-d 50 | output debugging info to stdout. 51 | .TP 52 | .B \-f 53 | ignore an already existing lock file. 54 | .TP 55 | .BI \-p\ devfile \fR,\ \fB\-\-port= devfile 56 | use the specified serial port device (default 57 | .BR /dev/ttyS0 ). 58 | .TP 59 | .BI \-s\ speed \fR,\ \fB\-\-speed= speed 60 | use specified baudrate (default \fB115200\fR). 61 | .TP 62 | .BI \-t\ host\fB:\fIport \fR,\ \fB\-\-telnet= host\fB:\fIport 63 | work in telnet (rfc2217) mode. 64 | .TP 65 | .BI \-c\ interface\fB:\fIrx_id\fB:\fItx_id\fR,\ \fI \-\-can= interface\fB:\fIrx_id\fB:\fItx_id 66 | work in CAN mode (default: \fBcan0:200:200\fR) 67 | .TP 68 | .BR -h ", " \-\-help 69 | Show help. 70 | 71 | .SH "AUTHOR" 72 | .PP 73 | This manual page was written by Uwe Kleine-K\(:onig based on work initially 74 | done by Alexander Reichle-Schmehl. 75 | -------------------------------------------------------------------------------- /microcom.c: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | ** File: microcom.c 3 | ** Description: the main file for microcom project 4 | ** 5 | ** Copyright (C)1999 Anca and Lucian Jurubita . 6 | ** All rights reserved. 7 | **************************************************************************** 8 | ** This program is free software; you can redistribute it and/or 9 | ** modify it under the terms of the GNU General Public License 10 | ** as published by the Free Software Foundation; either version 2 11 | ** of the License, or (at your option) any later version. 12 | ** 13 | ** This program is distributed in the hope that it will be useful, 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ** GNU General Public License for more details at www.gnu.org 17 | **************************************************************************** 18 | ** Rev. 1.0 - Feb. 2000 19 | ** Rev. 1.01 - March 2000 20 | ** Rev. 1.02 - June 2000 21 | ****************************************************************************/ 22 | #define _GNU_SOURCE 23 | #include "microcom.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include "config.h" 34 | 35 | static struct termios sots; /* old stdout/in termios settings to restore */ 36 | 37 | struct ios_ops *ios; 38 | int debug; 39 | 40 | void init_terminal(void) 41 | { 42 | struct termios sts; 43 | 44 | memcpy(&sts, &sots, sizeof (sots)); /* to be used upon exit */ 45 | 46 | /* again, some arbitrary things */ 47 | sts.c_iflag &= ~(IGNCR | INLCR | ICRNL); 48 | sts.c_iflag |= IGNBRK; 49 | sts.c_lflag &= ~ISIG; 50 | sts.c_cc[VMIN] = 1; 51 | sts.c_cc[VTIME] = 0; 52 | sts.c_lflag &= ~ICANON; 53 | /* no local echo: allow the other end to do the echoing */ 54 | sts.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); 55 | 56 | tcsetattr(STDIN_FILENO, TCSANOW, &sts); 57 | } 58 | 59 | void restore_terminal(void) 60 | { 61 | tcsetattr(STDIN_FILENO, TCSANOW, &sots); 62 | } 63 | 64 | 65 | void microcom_exit(int signal) 66 | { 67 | printf("exiting\n"); 68 | 69 | ios->exit(ios); 70 | tcsetattr(STDIN_FILENO, TCSANOW, &sots); 71 | 72 | exit(0); 73 | } 74 | 75 | /******************************************************************** 76 | Main functions 77 | ******************************************************************** 78 | static void help_usage(int exitcode, char *error, char *addl) 79 | help with running the program 80 | - exitcode - to be returned when the program is ended 81 | - error - error string to be printed 82 | - addl - another error string to be printed 83 | static void cleanup_termios(int signal) 84 | signal handler to restore terminal set befor exit 85 | int main(int argc, char *argv[]) - 86 | main program function 87 | ********************************************************************/ 88 | void main_usage(int exitcode, char *str, char *dev) 89 | { 90 | fprintf(stderr, "Usage: microcom [options]\n" 91 | " [options] include:\n" 92 | " -p, --port= use the specified serial port device (%s);\n" 93 | " -s, --speed= use specified baudrate (%d)\n" 94 | " -t, --telnet= work in telnet (rfc2217) mode\n" 95 | " -c, --can= work in CAN mode\n" 96 | " default: (%s:%x:%x)\n" 97 | " -f, --force ignore existing lock file\n" 98 | " -d, --debug output debugging info\n" 99 | " -l, --logfile= log output to \n" 100 | " -o, --listenonly Do not modify local terminal, do not send input\n" 101 | " from stdin\n" 102 | " -a, --answerback= specify the answerback string sent as response to\n" 103 | " an ENQ (ASCII 0x05) Character\n" 104 | " -v, --version print version string\n" 105 | " -h, --help This help\n", 106 | DEFAULT_DEVICE, DEFAULT_BAUDRATE, 107 | DEFAULT_CAN_INTERFACE, DEFAULT_CAN_ID, DEFAULT_CAN_ID); 108 | fprintf(stderr, "Exitcode %d - %s %s\n\n", exitcode, str, dev); 109 | exit(exitcode); 110 | } 111 | 112 | int opt_force = 0; 113 | unsigned long current_speed = DEFAULT_BAUDRATE; 114 | int current_flow = FLOW_NONE; 115 | int listenonly = 0; 116 | 117 | int main(int argc, char *argv[]) 118 | { 119 | struct sigaction sact; /* used to initialize the signal handler */ 120 | int opt, ret; 121 | char *hostport = NULL; 122 | int telnet = 0, can = 0; 123 | char *interfaceid = NULL; 124 | char *device = DEFAULT_DEVICE; 125 | char *logfile = NULL; 126 | 127 | struct option long_options[] = { 128 | { "help", no_argument, NULL, 'h' }, 129 | { "port", required_argument, NULL, 'p'}, 130 | { "speed", required_argument, NULL, 's'}, 131 | { "telnet", required_argument, NULL, 't'}, 132 | { "can", required_argument, NULL, 'c'}, 133 | { "debug", no_argument, NULL, 'd' }, 134 | { "force", no_argument, NULL, 'f' }, 135 | { "logfile", required_argument, NULL, 'l'}, 136 | { "listenonly", no_argument, NULL, 'o'}, 137 | { "answerback", required_argument, NULL, 'a'}, 138 | { "version", no_argument, NULL, 'v' }, 139 | { }, 140 | }; 141 | 142 | while ((opt = getopt_long(argc, argv, "hp:s:t:c:dfl:oi:a:v", long_options, NULL)) != -1) { 143 | switch (opt) { 144 | case '?': 145 | main_usage(1, "", ""); 146 | break; 147 | case 'h': 148 | main_usage(0, "", ""); 149 | break; 150 | case 'v': 151 | printf("%s\n", PACKAGE_VERSION); 152 | exit(EXIT_SUCCESS); 153 | break; 154 | case 'p': 155 | device = optarg; 156 | break; 157 | case 's': 158 | current_speed = strtoul(optarg, NULL, 0); 159 | break; 160 | case 't': 161 | telnet = 1; 162 | hostport = optarg; 163 | break; 164 | case 'c': 165 | can = 1; 166 | interfaceid = optarg; 167 | break; 168 | case 'f': 169 | opt_force = 1; 170 | break; 171 | case 'd': 172 | debug = 1; 173 | break; 174 | case 'l': 175 | logfile = optarg; 176 | break; 177 | case 'o': 178 | listenonly = 1; 179 | break; 180 | case 'a': 181 | answerback = optarg; 182 | break; 183 | } 184 | } 185 | 186 | if (answerback) { 187 | ret = asprintf(&answerback, "%s\n", answerback); 188 | if (ret < 0) 189 | exit (1); 190 | } 191 | 192 | commands_init(); 193 | commands_fsl_imx_init(); 194 | 195 | if (telnet && can) 196 | main_usage(1, "", ""); 197 | 198 | if (telnet) 199 | ios = telnet_init(hostport); 200 | else if (can) { 201 | #ifdef USE_CAN 202 | ios = can_init(interfaceid); 203 | #else 204 | fprintf(stderr, "CAN mode not supported\n"); 205 | exit(EXIT_FAILURE); 206 | #endif 207 | } else 208 | ios = serial_init(device); 209 | 210 | if (!ios) 211 | exit(1); 212 | 213 | if (logfile) { 214 | ret = logfile_open(logfile); 215 | if (ret < 0) 216 | exit(1); 217 | } 218 | 219 | ret = ios->set_speed(ios, current_speed); 220 | if (ret) 221 | goto cleanup_ios; 222 | 223 | current_flow = FLOW_NONE; 224 | ios->set_flow(ios, current_flow); 225 | 226 | if (!listenonly) { 227 | printf("Escape character: Ctrl-\\\n"); 228 | printf("Type the escape character to get to the prompt.\n"); 229 | 230 | /* Now deal with the local terminal side */ 231 | tcgetattr(STDIN_FILENO, &sots); 232 | init_terminal(); 233 | 234 | /* set the signal handler to restore the old 235 | * termios handler */ 236 | sact.sa_handler = µcom_exit; 237 | sigaction(SIGHUP, &sact, NULL); 238 | sigaction(SIGINT, &sact, NULL); 239 | sigaction(SIGPIPE, &sact, NULL); 240 | sigaction(SIGTERM, &sact, NULL); 241 | sigaction(SIGQUIT, &sact, NULL); 242 | } 243 | 244 | /* run the main program loop */ 245 | ret = mux_loop(ios); 246 | 247 | if (!listenonly) 248 | tcsetattr(STDIN_FILENO, TCSANOW, &sots); 249 | 250 | cleanup_ios: 251 | ios->exit(ios); 252 | 253 | exit(ret ? 1 : 0); 254 | } 255 | -------------------------------------------------------------------------------- /microcom.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** File: microcom.h 3 | ** Description: the main header file for microcom project 4 | ** 5 | ** Copyright (C)1999 Anca and Lucian Jurubita . 6 | ** All rights reserved. 7 | **************************************************************************** 8 | ** This program is free software; you can redistribute it and/or 9 | ** modify it under the terms of the GNU General Public License 10 | ** as published by the Free Software Foundation; either version 2 11 | ** of the License, or (at your option) any later version. 12 | ** 13 | ** This program is distributed in the hope that it will be useful, 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ** GNU General Public License for more details at www.gnu.org 17 | **************************************************************************** 18 | ** Rev. 1.0 - Feb. 2000 19 | ** Rev. 1.02 - June 2000 20 | ****************************************************************************/ 21 | #ifndef MICROCOM_H 22 | #define MICROCOM_H 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #define DEFAULT_BAUDRATE 115200 37 | #define DEFAULT_DEVICE "/dev/ttyS0" 38 | #define DEFAULT_CAN_INTERFACE "can0" 39 | #define DEFAULT_CAN_ID (0x200) 40 | 41 | struct ios_ops { 42 | ssize_t (*write)(struct ios_ops *, const void *buf, size_t count); 43 | ssize_t (*read)(struct ios_ops *, void *buf, size_t count); 44 | int (*set_speed)(struct ios_ops *, unsigned long speed); 45 | #define FLOW_NONE 0 46 | #define FLOW_SOFT 1 47 | #define FLOW_HARD 2 48 | int (*set_flow)(struct ios_ops *, int flow); 49 | #define PIN_DTR 1 50 | #define PIN_RTS 2 51 | int (*set_handshake_line)(struct ios_ops *, int pin, int enable); 52 | int (*send_break)(struct ios_ops *); 53 | void (*exit)(struct ios_ops *); 54 | int fd; 55 | }; 56 | 57 | int mux_loop(struct ios_ops *); /* mux.c */ 58 | void init_terminal(void); 59 | void restore_terminal(void); 60 | 61 | struct ios_ops *telnet_init(char *hostport); 62 | struct ios_ops *serial_init(char *dev); 63 | struct ios_ops *can_init(char *interfaceid); 64 | 65 | void microcom_exit(int signal); 66 | 67 | void microcom_cmd_usage(char *str); 68 | 69 | void main_usage(int exitcode, char *str, char *dev); 70 | 71 | extern struct ios_ops *ios; 72 | extern int debug; 73 | extern int opt_force; 74 | extern int listenonly; 75 | extern char *answerback; 76 | 77 | struct cmd { 78 | char *name; 79 | int(*fn)(int argc, char *argv[]); 80 | struct cmd *next; 81 | char *info; 82 | char *help; 83 | }; 84 | 85 | int logfile_open(const char *path); 86 | void logfile_close(void); 87 | 88 | int register_command(struct cmd *cmd); 89 | #define MICROCOM_CMD_START 100 90 | #define MICROCOM_CMD_USAGE 101 91 | extern struct cmd *commands; 92 | 93 | #define for_each_command(cmd) for (cmd = commands; cmd; cmd = cmd->next) 94 | 95 | void commands_init(void); 96 | void commands_fsl_imx_init(void); 97 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 98 | 99 | /* 100 | * min()/max()/clamp() macros that also do 101 | * strict type-checking.. See the 102 | * "unnecessary" pointer comparison. 103 | */ 104 | #define min(x, y) ({ \ 105 | typeof(x) _min1 = (x); \ 106 | typeof(y) _min2 = (y); \ 107 | (void) (&_min1 == &_min2); \ 108 | _min1 < _min2 ? _min1 : _min2; }) 109 | 110 | #define max(x, y) ({ \ 111 | typeof(x) _max1 = (x); \ 112 | typeof(y) _max2 = (y); \ 113 | (void) (&_max1 == &_max2); \ 114 | _max1 > _max2 ? _max1 : _max2; }) 115 | 116 | extern unsigned long current_speed; 117 | extern int current_flow; 118 | int do_commandline(void); 119 | int do_script(char *script); 120 | 121 | #define dbg_printf(fmt,args...) ({ if (debug) printf(fmt ,##args); }) 122 | 123 | /* 124 | * Some telnet options according to 125 | * https://www.iana.org/assignments/telnet-options/telnet-options.xhtmls 126 | */ 127 | 128 | #define TELNET_OPTION_BINARY_TRANSMISSION 0 129 | #define TELNET_OPTION_ECHO 1 130 | #define TELNET_OPTION_SUPPRESS_GO_AHEAD 3 131 | #define TELNET_OPTION_COM_PORT_CONTROL 44 132 | 133 | /* RFC2217 */ 134 | #define SET_BAUDRATE_CS 1 135 | #define SET_DATASIZE_CS 2 136 | #define SET_PARITY_CS 3 137 | #define SET_STOPSIZE_CS 4 138 | #define SET_CONTROL_CS 5 139 | #define NOTIFY_LINESTATE_CS 6 140 | #define NOTIFY_MODEMSTATE_CS 7 141 | #define FLOWCONTROL_SUSPEND_CS 8 142 | #define FLOWCONTROL_RESUME_CS 9 143 | #define SET_LINESTATE_MASK_CS 10 144 | #define SET_MODEMSTATE_MASK_CS 11 145 | #define PURGE_DATA_CS 12 146 | #define SET_BAUDRATE_SC 101 147 | #define SET_DATASIZE_SC 102 148 | #define SET_PARITY_SC 103 149 | #define SET_STOPSIZE_SC 104 150 | #define SET_CONTROL_SC 105 151 | #define NOTIFY_LINESTATE_SC 106 152 | #define NOTIFY_MODEMSTATE_SC 107 153 | #define FLOWCONTROL_SUSPEND_SC 108 154 | #define FLOWCONTROL_RESUME_SC 109 155 | #define SET_LINESTATE_MASK_SC 110 156 | #define SET_MODEMSTATE_MASK_SC 111 157 | #define PURGE_DATA_SC 112 158 | 159 | #endif /* MICROCOM_H */ 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /mux.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | ** File: mux.c 3 | ** Description: the main program loop 4 | ** 5 | ** Copyright (C)1999 Anca and Lucian Jurubita . 6 | ** All rights reserved. 7 | **************************************************************************** 8 | ** This program is free software; you can redistribute it and/or 9 | ** modify it under the terms of the GNU General Public License 10 | ** as published by the Free Software Foundation; either version 2 11 | ** of the License, or (at your option) any later version. 12 | ** 13 | ** This program is distributed in the hope that it will be useful, 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ** GNU General Public License for more details at www.gnu.org 17 | **************************************************************************** 18 | ** Rev. 1.0 - Feb. 2000 19 | ****************************************************************************/ 20 | #include "config.h" 21 | 22 | #include "microcom.h" 23 | #include 24 | 25 | #define BUFSIZE 1024 26 | 27 | static int logfd = -1; 28 | char *answerback; 29 | 30 | static void write_receive_buf(const unsigned char *buf, int len) 31 | { 32 | if (!len) 33 | return; 34 | 35 | write(STDOUT_FILENO, buf, len); 36 | if (logfd >= 0) 37 | write(logfd, buf, len); 38 | } 39 | 40 | static int handle_receive_buf(struct ios_ops *ios, unsigned char *buf, int len) 41 | { 42 | unsigned char *sendbuf = buf; 43 | 44 | while (len) { 45 | switch (*buf) { 46 | case 5: 47 | write_receive_buf(sendbuf, buf - sendbuf); 48 | if (answerback) 49 | ios->write(ios, answerback, strlen(answerback)); 50 | else 51 | write_receive_buf(buf, 1); 52 | 53 | buf += 1; 54 | len -= 1; 55 | sendbuf = buf; 56 | break; 57 | default: 58 | buf += 1; 59 | len -= 1; 60 | break; 61 | } 62 | } 63 | 64 | write_receive_buf(sendbuf, buf - sendbuf); 65 | return 0; 66 | } 67 | 68 | /* handle escape characters, writing to output */ 69 | static void cook_buf(struct ios_ops *ios, unsigned char *buf, int num) 70 | { 71 | int current = 0; 72 | 73 | while (current < num) { /* big while loop, to process all the charactes in buffer */ 74 | 75 | /* look for the next escape character (Ctrl-\) */ 76 | while ((current < num) && (buf[current] != 28)) 77 | current++; 78 | /* and write the sequence before esc char to the comm port */ 79 | if (current) 80 | ios->write(ios, buf, current); 81 | 82 | if (current < num) { /* process an escape sequence */ 83 | /* found an escape character */ 84 | do_commandline(); 85 | return; 86 | } /* if - end of processing escape sequence */ 87 | num -= current; 88 | buf += current; 89 | current = 0; 90 | } /* while - end of processing all the charactes in the buffer */ 91 | } 92 | 93 | void logfile_close(void) 94 | { 95 | if (logfd >= 0) 96 | close(logfd); 97 | 98 | logfd = -1; 99 | } 100 | 101 | int logfile_open(const char *path) 102 | { 103 | int fd; 104 | 105 | fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0644); 106 | if (fd < 0) { 107 | fprintf(stderr, "Cannot open logfile '%s': %s\n", path, strerror(errno)); 108 | return fd; 109 | } 110 | 111 | if (logfd >= 0) 112 | logfile_close(); 113 | 114 | logfd = fd; 115 | 116 | return 0; 117 | } 118 | 119 | /* main program loop */ 120 | int mux_loop(struct ios_ops *ios) 121 | { 122 | fd_set ready; /* used for select */ 123 | int i = 0, len; /* used in the multiplex loop */ 124 | unsigned char buf[BUFSIZE]; 125 | 126 | while (1) { 127 | int ret; 128 | 129 | FD_ZERO(&ready); 130 | if (!listenonly) 131 | FD_SET(STDIN_FILENO, &ready); 132 | FD_SET(ios->fd, &ready); 133 | 134 | select(ios->fd + 1, &ready, NULL, NULL, NULL); 135 | 136 | if (FD_ISSET(ios->fd, &ready)) { 137 | /* pf has characters for us */ 138 | len = ios->read(ios, buf, BUFSIZE); 139 | if (len < 0) { 140 | if (errno != EAGAIN && errno != EWOULDBLOCK) { 141 | ret = -errno; 142 | fprintf(stderr, "%s\n", strerror(-ret)); 143 | return ret; 144 | } 145 | } else if (len == 0) { 146 | fprintf(stderr, "Got EOF from port\n"); 147 | return -EINVAL; 148 | } else { 149 | i = handle_receive_buf(ios, buf, len); 150 | if (i < 0) { 151 | fprintf(stderr, "%s\n", strerror(-i)); 152 | return i; 153 | } 154 | } 155 | } 156 | 157 | if (!listenonly && FD_ISSET(STDIN_FILENO, &ready)) { 158 | /* standard input has characters for us */ 159 | i = read(STDIN_FILENO, buf, BUFSIZE); 160 | if (i < 0) { 161 | ret = -errno; 162 | fprintf(stderr, "%s\n", strerror(-ret)); 163 | return ret; 164 | } 165 | if (i == 0) { 166 | fprintf(stderr, "Got EOF from stdin\n"); 167 | return -EINVAL; 168 | } 169 | 170 | cook_buf(ios, buf, i); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 Sascha Hauer 3 | * 4 | * This program is free software; you can redistribute it and/or modify it under 5 | * the terms of the GNU General Public License as published by the Free Software 6 | * Foundation; either version 2 of the License, or (at your option) any later 7 | * version. 8 | */ 9 | #include "config.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include "microcom.h" 15 | 16 | #define MAXARGS 64 17 | 18 | static int parse_line(char *_line, int *argc, char *argv[]) 19 | { 20 | char *line = _line; 21 | int nargs = 0; 22 | 23 | if (!line) 24 | goto out; 25 | 26 | while (nargs < MAXARGS) { 27 | 28 | /* skip any white space */ 29 | while (*line == ' ' || *line == '\t') 30 | ++line; 31 | 32 | if (*line == '\0' || *line == ';') /* end of line, no more args */ 33 | goto out; 34 | 35 | argv[nargs] = line; /* begin of argument string */ 36 | 37 | if (*line == '\"') { 38 | line++; 39 | argv[nargs] = line; 40 | while (*line && *line != '\"') 41 | line++; 42 | if (!*line) { 43 | printf("could not find matching '\"'\n"); 44 | return -EINVAL; 45 | } else 46 | *line++ = '\0'; 47 | } else { 48 | /* find end of string */ 49 | while (*line && *line != ' ' && *line != '\t' && *line != ';') 50 | ++line; 51 | } 52 | 53 | nargs++; 54 | 55 | 56 | if (*line == '\0') /* end of line, no more args */ 57 | goto out; 58 | if (*line == ';') { 59 | *line = '\0'; 60 | goto out; 61 | } 62 | 63 | *line++ = '\0'; /* terminate current arg */ 64 | } 65 | 66 | printf("Too many args (max. %d)\n", MAXARGS); 67 | out: 68 | argv[nargs] = NULL; 69 | *argc = nargs; 70 | 71 | return line - _line + 1; 72 | } 73 | 74 | struct cmd *commands; 75 | 76 | int register_command(struct cmd *cmd) 77 | { 78 | struct cmd *tmp; 79 | 80 | cmd->next = NULL; 81 | 82 | if (!commands) { 83 | commands = cmd; 84 | return 0; 85 | } 86 | 87 | tmp = commands; 88 | 89 | while (tmp->next) 90 | tmp = tmp->next; 91 | 92 | tmp->next = cmd; 93 | 94 | return 0; 95 | } 96 | 97 | void microcom_cmd_usage(char *command) 98 | { 99 | struct cmd *cmd; 100 | 101 | for_each_command(cmd) { 102 | if (!strcmp(command, cmd->name)) { 103 | char *str = NULL; 104 | if (cmd->info) 105 | str = cmd->info; 106 | if (cmd->help) 107 | str = cmd->help; 108 | if (!str) 109 | str = "no help available\n"; 110 | printf("usage:\n%s\n", str); 111 | return; 112 | } 113 | } 114 | printf("no such command\n"); 115 | } 116 | 117 | static int __do_commandline(const char *prompt) 118 | { 119 | char *cmd; 120 | char *argv[MAXARGS + 1]; 121 | int argc = 0, ret = 0, n, len; 122 | 123 | while (1) { 124 | struct cmd *command; 125 | cmd = readline(prompt); 126 | if (!cmd) { 127 | ret = MICROCOM_CMD_START; 128 | break; 129 | } 130 | 131 | if (!strlen(cmd)) 132 | goto done; 133 | 134 | if (prompt) 135 | add_history(cmd); 136 | 137 | len = strlen(cmd); 138 | n = 0; 139 | while (n < len) { 140 | int handled = 0; 141 | ret = parse_line(cmd + n, &argc, argv); 142 | if (ret < 0) 143 | break; 144 | n += ret; 145 | if (!argv[0]) 146 | continue; 147 | 148 | for_each_command(command) { 149 | if (!strcmp(argv[0], command->name)) { 150 | ret = command->fn(argc, argv); 151 | if (ret == MICROCOM_CMD_START) { 152 | free(cmd); 153 | return ret; 154 | } 155 | 156 | if (ret == MICROCOM_CMD_USAGE) 157 | microcom_cmd_usage(argv[0]); 158 | 159 | handled = 1; 160 | break; 161 | } 162 | } 163 | if (!handled) 164 | printf("unknown command \'%s\', try \'help\'\n", argv[0]); 165 | } 166 | done: 167 | free(cmd); 168 | } 169 | 170 | if (cmd) 171 | free(cmd); 172 | return ret; 173 | } 174 | 175 | int do_commandline(void) 176 | { 177 | int ret; 178 | 179 | restore_terminal(); 180 | printf("\nEnter command. Try \'help\' for a list of builtin commands\n"); 181 | 182 | do { 183 | ret = __do_commandline("-> "); 184 | } while (ret != MICROCOM_CMD_START); 185 | 186 | printf("\n----------------------\n"); 187 | init_terminal(); 188 | 189 | return 0; 190 | } 191 | 192 | int do_script(char *script) 193 | { 194 | int fd = open(script, O_RDONLY); 195 | int stdinfd = dup(1); 196 | int ret; 197 | 198 | if (fd < 0) { 199 | printf("could not open %s: %s\n", script, strerror(errno)); 200 | return -1; 201 | } 202 | 203 | dup2(fd, 0); 204 | ret = __do_commandline(NULL); 205 | dup2(stdinfd, 0); 206 | 207 | return ret; 208 | } 209 | 210 | -------------------------------------------------------------------------------- /serial.c: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | ** File: serial.c 3 | ** Description: the serial part for microcom project 4 | ** 5 | ** Copyright (C)1999 Anca and Lucian Jurubita . 6 | ** All rights reserved. 7 | **************************************************************************** 8 | ** This program is free software; you can redistribute it and/or 9 | ** modify it under the terms of the GNU General Public License 10 | ** as published by the Free Software Foundation; either version 2 11 | ** of the License, or (at your option) any later version. 12 | ** 13 | ** This program is distributed in the hope that it will be useful, 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ** GNU General Public License for more details at www.gnu.org 17 | **************************************************************************** 18 | ** Rev. 1.0 - Feb. 2000 19 | ** Rev. 1.01 - March 2000 20 | ** Rev. 1.02 - June 2000 21 | ****************************************************************************/ 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "microcom.h" 30 | 31 | static struct termios pots; /* old port termios settings to restore */ 32 | 33 | static void init_comm(struct termios *pts) 34 | { 35 | /* some things we want to set arbitrarily */ 36 | pts->c_lflag &= ~ICANON; 37 | pts->c_lflag &= ~(ECHO | ECHOCTL | ECHONL); 38 | pts->c_cflag |= HUPCL | CREAD | CLOCAL; 39 | pts->c_iflag |= IGNBRK; 40 | pts->c_cc[VMIN] = 1; 41 | pts->c_cc[VTIME] = 0; 42 | 43 | /* Standard CR/LF handling: this is a dumb terminal. 44 | * Do no translation: 45 | * no NL -> CR/NL mapping on output, and 46 | * no CR -> NL mapping on input. 47 | */ 48 | pts->c_oflag &= ~ONLCR; 49 | pts->c_iflag &= ~ICRNL; 50 | } 51 | 52 | static ssize_t serial_write(struct ios_ops *ios, const void *buf, size_t count) 53 | { 54 | return write(ios->fd, buf, count); 55 | } 56 | 57 | static ssize_t serial_read(struct ios_ops *ios, void *buf, size_t count) 58 | { 59 | return read(ios->fd, buf, count); 60 | } 61 | 62 | static int serial_set_handshake_line(struct ios_ops *ios, int pin, int enable) 63 | { 64 | int flag; 65 | int ret; 66 | 67 | switch (pin) { 68 | case PIN_DTR: 69 | flag = TIOCM_DTR; 70 | break; 71 | case PIN_RTS: 72 | flag = TIOCM_RTS; 73 | break; 74 | } 75 | 76 | if (enable) 77 | ret = ioctl(ios->fd, TIOCMBIS, &flag); 78 | else 79 | ret = ioctl(ios->fd, TIOCMBIC, &flag); 80 | 81 | return ret; 82 | } 83 | 84 | static const struct { 85 | int speed; 86 | speed_t flag; 87 | } bd_to_flg[] = { 88 | { 50, B50 }, 89 | { 75, B75 }, 90 | { 110, B110 }, 91 | { 134, B134 }, 92 | { 150, B150 }, 93 | { 200, B200 }, 94 | { 300, B300 }, 95 | { 600, B600 }, 96 | { 1200, B1200}, 97 | { 1800, B1800}, 98 | { 2400, B2400}, 99 | { 4800, B4800}, 100 | { 9600, B9600}, 101 | { 19200, B19200}, 102 | { 38400, B38400}, 103 | { 57600, B57600}, 104 | { 115200, B115200}, 105 | { 230400, B230400}, 106 | #ifdef B460800 107 | { 460800, B460800}, 108 | #endif 109 | #ifdef B500000 110 | { 500000, B500000}, 111 | #endif 112 | #ifdef B576000 113 | { 576000, B576000}, 114 | #endif 115 | #ifdef B921600 116 | { 921600, B921600}, 117 | #endif 118 | #ifdef B1000000 119 | { 1000000, B1000000}, 120 | #endif 121 | #ifdef B1152000 122 | { 1152000, B1152000}, 123 | #endif 124 | #ifdef B1500000 125 | { 1500000, B1500000}, 126 | #endif 127 | #ifdef B2000000 128 | { 2000000, B2000000}, 129 | #endif 130 | #ifdef B2500000 131 | { 2500000, B2500000}, 132 | #endif 133 | #ifdef B3000000 134 | { 3000000, B3000000}, 135 | #endif 136 | #ifdef B3500000 137 | { 3500000, B3500000}, 138 | #endif 139 | #ifdef B4000000 140 | { 4000000, B4000000}, 141 | #endif 142 | }; 143 | 144 | static int baudrate_to_flag(int speed, speed_t *flag) 145 | { 146 | size_t i; 147 | 148 | /* possible optimisation: binary search for speed */ 149 | for (i = 0; i < ARRAY_SIZE(bd_to_flg); ++i) 150 | if (bd_to_flg[i].speed == speed) { 151 | *flag = bd_to_flg[i].flag; 152 | return 0; 153 | } 154 | 155 | return -1; 156 | } 157 | 158 | static int serial_set_speed(struct ios_ops *ios, unsigned long speed) 159 | { 160 | struct termios pts; /* termios settings on port */ 161 | speed_t flag; 162 | int ret; 163 | 164 | tcgetattr(ios->fd, &pts); 165 | 166 | ret = baudrate_to_flag(speed, &flag); 167 | if (ret) 168 | return ret; 169 | 170 | cfsetospeed(&pts, flag); 171 | cfsetispeed(&pts, flag); 172 | tcsetattr(ios->fd, TCSANOW, &pts); 173 | 174 | return 0; 175 | } 176 | 177 | static int serial_set_flow(struct ios_ops *ios, int flow) 178 | { 179 | struct termios pts; /* termios settings on port */ 180 | tcgetattr(ios->fd, &pts); 181 | 182 | switch (flow) { 183 | case FLOW_NONE: 184 | /* no flow control */ 185 | pts.c_cflag &= ~CRTSCTS; 186 | pts.c_iflag &= ~(IXON | IXOFF | IXANY); 187 | break; 188 | case FLOW_HARD: 189 | /* hardware flow control */ 190 | pts.c_cflag |= CRTSCTS; 191 | pts.c_iflag &= ~(IXON | IXOFF | IXANY); 192 | break; 193 | case FLOW_SOFT: 194 | /* software flow control */ 195 | pts.c_cflag &= ~CRTSCTS; 196 | pts.c_iflag |= IXON | IXOFF | IXANY; 197 | break; 198 | } 199 | 200 | tcsetattr(ios->fd, TCSANOW, &pts); 201 | 202 | return 0; 203 | } 204 | 205 | static int serial_send_break(struct ios_ops *ios) 206 | { 207 | int ret; 208 | struct timeval delay = { 209 | .tv_sec = 0, 210 | .tv_usec = 400000, 211 | }; 212 | 213 | ret = ioctl(ios->fd, TIOCSBRK, NULL); 214 | if (ret < 0) 215 | return ret; 216 | 217 | select(0, NULL, NULL, NULL, &delay); 218 | 219 | ret = ioctl(ios->fd, TIOCCBRK, NULL); 220 | return ret; 221 | } 222 | 223 | /* restore original terminal settings on exit */ 224 | static void serial_exit(struct ios_ops *ios) 225 | { 226 | tcsetattr(ios->fd, TCSANOW, &pots); 227 | close(ios->fd); 228 | free(ios); 229 | } 230 | 231 | struct ios_ops * serial_init(char *device) 232 | { 233 | struct termios pts; /* termios settings on port */ 234 | struct ios_ops *ops; 235 | int fd, ret; 236 | 237 | ops = malloc(sizeof(*ops)); 238 | if (!ops) 239 | return NULL; 240 | 241 | ops->write = serial_write; 242 | ops->read = serial_read; 243 | ops->set_speed = serial_set_speed; 244 | ops->set_flow = serial_set_flow; 245 | ops->set_handshake_line = serial_set_handshake_line; 246 | ops->send_break = serial_send_break; 247 | ops->exit = serial_exit; 248 | 249 | /* open the device */ 250 | fd = open(device, O_RDWR | O_NONBLOCK); 251 | ops->fd = fd; 252 | 253 | if (fd < 0) 254 | main_usage(2, "cannot open device", device); 255 | 256 | /* try to lock the device */ 257 | ret = flock(fd, LOCK_EX | LOCK_NB); 258 | if (ret) { 259 | if (!opt_force) 260 | main_usage(3, "could not lock port", device); 261 | else 262 | printf("could not lock port, ignoring\n"); 263 | } 264 | 265 | /* modify the port configuration */ 266 | tcgetattr(fd, &pts); 267 | memcpy(&pots, &pts, sizeof (pots)); 268 | init_comm(&pts); 269 | tcsetattr(fd, TCSANOW, &pts); 270 | printf("connected to %s\n", device); 271 | 272 | return ops; 273 | } 274 | 275 | -------------------------------------------------------------------------------- /telnet.c: -------------------------------------------------------------------------------- 1 | /****************************************************************** 2 | ** File: telnet.c 3 | ** Description: the telnet part for microcom project 4 | ** 5 | ** Copyright (C) 2008, 2009 Sascha Hauer . 6 | ** All rights reserved. 7 | **************************************************************************** 8 | ** This program is free software; you can redistribute it and/or 9 | ** modify it under the terms of the GNU General Public License 10 | ** as published by the Free Software Foundation; either version 2 11 | ** of the License, or (at your option) any later version. 12 | ** 13 | ** This program is distributed in the hope that it will be useful, 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ** GNU General Public License for more details at www.gnu.org 17 | ****************************************************************************/ 18 | #include "config.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "microcom.h" 31 | 32 | static int telnet_printf(struct ios_ops *ios, const char *format, ...) 33 | { 34 | char buf[20]; 35 | int size, written = 0; 36 | ssize_t ret; 37 | va_list args; 38 | 39 | va_start(args, format); 40 | 41 | size = vsnprintf(buf, sizeof(buf), format, args); 42 | 43 | va_end(args); 44 | 45 | if (size >= sizeof(buf)) { 46 | /* truncated output */ 47 | errno = EIO; 48 | return -1; 49 | } 50 | 51 | while (written < size) { 52 | ret = write(ios->fd, buf + written, size - written); 53 | if (ret < 0) 54 | return ret; 55 | 56 | written += ret; 57 | assert(written <= size); 58 | } 59 | 60 | return written; 61 | } 62 | 63 | static ssize_t get(unsigned char *buf, unsigned char *out, size_t len) 64 | { 65 | if (!len) 66 | return -1; 67 | 68 | if (buf[0] == IAC) { 69 | if (len < 1) 70 | return -1; 71 | if (buf[1] == IAC) { 72 | *out = IAC; 73 | return 2; 74 | } 75 | return -1; 76 | } else { 77 | *out = buf[0]; 78 | return 1; 79 | } 80 | } 81 | 82 | static size_t getl(unsigned char *buf, uint32_t *out, size_t len) 83 | { 84 | *out = 0; 85 | int i; 86 | size_t offset = 0; 87 | 88 | for (i = 0; i < 4; ++i) { 89 | ssize_t getres; 90 | unsigned char c; 91 | 92 | getres = get(buf + offset, &c, len - offset); 93 | if (getres < 0) 94 | return getres; 95 | 96 | *out <<= 8; 97 | *out |= c; 98 | 99 | offset += getres; 100 | } 101 | 102 | return offset; 103 | } 104 | 105 | /* This is called with buf[-2:0] being IAC SB COM_PORT_OPTION */ 106 | static int do_com_port_option(struct ios_ops *ios, unsigned char *buf, int len) 107 | { 108 | int i = 2; 109 | 110 | switch (buf[1]) { 111 | case SET_BAUDRATE_CS: 112 | dbg_printf("SET_BAUDRATE_CS "); 113 | break; 114 | case SET_DATASIZE_CS: 115 | dbg_printf("SET_DATASIZE_CS "); 116 | break; 117 | case SET_PARITY_CS: 118 | dbg_printf("SET_PARITY_CS "); 119 | break; 120 | case SET_STOPSIZE_CS: 121 | dbg_printf("SET_STOPSIZE_CS "); 122 | break; 123 | case SET_CONTROL_CS: 124 | dbg_printf("SET_CONTROL_CS "); 125 | break; 126 | case NOTIFY_LINESTATE_CS: 127 | dbg_printf("NOTIFY_LINESTATE_CS "); 128 | break; 129 | case NOTIFY_MODEMSTATE_CS: 130 | dbg_printf("NOTIFY_MODEMSTATE_CS "); 131 | break; 132 | case FLOWCONTROL_SUSPEND_CS: 133 | dbg_printf("FLOWCONTROL_SUSPEND_CS "); 134 | break; 135 | case FLOWCONTROL_RESUME_CS: 136 | dbg_printf("FLOWCONTROL_RESUME_CS "); 137 | break; 138 | case SET_LINESTATE_MASK_CS: 139 | dbg_printf("SET_LINESTATE_MASK_CS "); 140 | break; 141 | case SET_MODEMSTATE_MASK_CS: 142 | dbg_printf("SET_MODEMSTATE_MASK_CS "); 143 | break; 144 | case PURGE_DATA_CS: 145 | dbg_printf("PURGE_DATA_CS "); 146 | break; 147 | case SET_BAUDRATE_SC: 148 | { 149 | uint32_t baudrate; 150 | ssize_t getres = getl(buf + 2, &baudrate, len - 2); 151 | 152 | if (getres < 0) { 153 | fprintf(stderr, "Incomplete or broken SB (SET_BAUDRATE_SC)\n"); 154 | return getres; 155 | } 156 | dbg_printf("SET_BAUDRATE_SC %u ", baudrate); 157 | i += getres;; 158 | } 159 | break; 160 | case SET_DATASIZE_SC: 161 | dbg_printf("SET_DATASIZE_SC "); 162 | break; 163 | case SET_PARITY_SC: 164 | dbg_printf("SET_PARITY_SC "); 165 | break; 166 | case SET_STOPSIZE_SC: 167 | dbg_printf("SET_STOPSIZE_SC "); 168 | break; 169 | case SET_CONTROL_SC: 170 | { 171 | unsigned char ctrl; 172 | ssize_t getres = get(buf + 2, &ctrl, len - 2); 173 | 174 | if (getres < 0) { 175 | fprintf(stderr, "Incomplete or broken SB (SET_CONTROL_SC)\n"); 176 | return getres; 177 | } 178 | 179 | dbg_printf("SET_CONTROL_SC 0x%02x ", ctrl); 180 | i += getres; 181 | } 182 | break; 183 | case NOTIFY_LINESTATE_SC: 184 | dbg_printf("NOTIFY_LINESTATE_SC "); 185 | break; 186 | case NOTIFY_MODEMSTATE_SC: 187 | { 188 | unsigned char ms; 189 | ssize_t getres = get(buf + 2, &ms, len - 2); 190 | 191 | if (getres < 0) { 192 | fprintf(stderr, "Incomplete or broken SB (NOTIFY_MODEMSTATE_SC)\n"); 193 | return getres; 194 | } 195 | 196 | dbg_printf("NOTIFY_MODEMSTATE_SC 0x%02x ", ms); 197 | i += getres; 198 | } 199 | case FLOWCONTROL_SUSPEND_SC: 200 | dbg_printf("FLOWCONTROL_SUSPEND_SC "); 201 | break; 202 | case FLOWCONTROL_RESUME_SC: 203 | dbg_printf("FLOWCONTROL_RESUME_SC "); 204 | break; 205 | case SET_LINESTATE_MASK_SC: 206 | dbg_printf("SET_LINESTATE_MASK_SC "); 207 | break; 208 | case SET_MODEMSTATE_MASK_SC: 209 | dbg_printf("SET_MODEMSTATE_MASK_SC "); 210 | break; 211 | case PURGE_DATA_SC: 212 | dbg_printf("PURGE_DATA_SC "); 213 | break; 214 | default: 215 | dbg_printf("??? %d ", buf[1]); 216 | break; 217 | } 218 | 219 | while (i < len) { 220 | if (buf[i] == IAC) { 221 | if (i + 1 < len && buf[i+1] == IAC) { 222 | /* quoted IAC -> unquote */ 223 | ++i; 224 | } else if (i + 1 < len && buf[i+1] == SE) { 225 | dbg_printf("IAC SE\n"); 226 | return i + 2; 227 | } 228 | } 229 | dbg_printf("%d ", buf[i]); 230 | 231 | ++i; 232 | } 233 | 234 | fprintf(stderr, "Incomplete SB string\n"); 235 | return -EINVAL; 236 | } 237 | 238 | /* This is called with buf[-2:0] being IAC SB COM_PORT_OPTION */ 239 | static int do_binary_transmission_option(struct ios_ops *ios, unsigned char *buf, int len) 240 | { 241 | /* There are no subcommands for the BINARY_TRANSMISSION option (rfc856) */ 242 | return -EINVAL; 243 | } 244 | 245 | struct telnet_option { 246 | unsigned char id; 247 | const char *name; 248 | int (*subneg_handler)(struct ios_ops *ios, unsigned char *buf, int len); 249 | bool sent_will; 250 | }; 251 | 252 | #define TELNET_OPTION(x) .id = TELNET_OPTION_ ## x, .name = #x 253 | 254 | static const struct telnet_option telnet_options[] = { 255 | { 256 | TELNET_OPTION(COM_PORT_CONTROL), 257 | .subneg_handler = do_com_port_option, 258 | .sent_will = true, 259 | }, { 260 | TELNET_OPTION(BINARY_TRANSMISSION), 261 | .subneg_handler = do_binary_transmission_option, 262 | .sent_will = true, 263 | }, { 264 | TELNET_OPTION(ECHO), 265 | }, { 266 | TELNET_OPTION(SUPPRESS_GO_AHEAD), 267 | } 268 | }; 269 | 270 | static const struct telnet_option *get_telnet_option(unsigned char id) 271 | { 272 | int i; 273 | 274 | for (i = 0; i < ARRAY_SIZE(telnet_options); ++i) { 275 | if (id == telnet_options[i].id) 276 | return &telnet_options[i]; 277 | } 278 | 279 | return NULL; 280 | } 281 | 282 | 283 | /* This function is called with buf[-2:-1] being IAC SB */ 284 | static int do_subneg(struct ios_ops *ios, unsigned char *buf, int len) 285 | { 286 | const struct telnet_option *option = get_telnet_option(buf[0]); 287 | 288 | if (option) 289 | dbg_printf("%s ", option->name); 290 | if (option->subneg_handler) { 291 | return option->subneg_handler(ios, buf, len); 292 | } else { 293 | /* skip over subneg string */ 294 | int i; 295 | for (i = 0; i < len - 1; ++i) { 296 | if (buf[i] != IAC) { 297 | dbg_printf("%d ", buf[i]); 298 | continue; 299 | } 300 | 301 | if (buf[i + 1] == SE) { 302 | dbg_printf("IAC SE\n"); 303 | return i + 1; 304 | } 305 | 306 | /* skip over IAC IAC */ 307 | if (buf[i + 1] == IAC) { 308 | dbg_printf("%d \n", IAC); 309 | i++; 310 | } 311 | } 312 | 313 | /* the subneg string isn't finished yet */ 314 | if (i == len - 1) 315 | dbg_printf("%d", buf[i]); 316 | dbg_printf("\\\n"); 317 | fprintf(stderr, "Incomplete SB string\n"); 318 | 319 | return -EINVAL; 320 | } 321 | } 322 | 323 | /* This function is called with buf[0] being IAC. */ 324 | static int handle_command(struct ios_ops *ios, unsigned char *buf, int len) 325 | { 326 | int ret; 327 | const struct telnet_option *option; 328 | 329 | /* possible out-of-bounds access */ 330 | switch (buf[1]) { 331 | case SB: 332 | dbg_printf("SB "); 333 | ret = do_subneg(ios, &buf[2], len - 2); 334 | if (ret < 0) 335 | return ret; 336 | return ret + 2; 337 | 338 | case WILL: 339 | option = get_telnet_option(buf[2]); 340 | if (option) 341 | dbg_printf("WILL %s", option->name); 342 | else 343 | dbg_printf("WILL #%d", buf[2]); 344 | 345 | if (option && option->subneg_handler) { 346 | /* ok, we already requested that, so take this as 347 | * confirmation to actually do COM_PORT stuff. 348 | * Everything is fine. Don't reconfirm to prevent an 349 | * request/confirm storm. 350 | */ 351 | dbg_printf("\n"); 352 | } else { 353 | /* unknown/unimplemented option -> DONT */ 354 | dbg_printf(" -> DONT\n"); 355 | telnet_printf(ios, "%c%c%c", IAC, DONT, buf[2]); 356 | } 357 | return 3; 358 | 359 | case WONT: 360 | option = get_telnet_option(buf[2]); 361 | if (option) 362 | dbg_printf("WONT %s\n", option->name); 363 | else 364 | dbg_printf("WONT #%d\n", buf[2]); 365 | return 3; 366 | 367 | case DO: 368 | option = get_telnet_option(buf[2]); 369 | if (option) 370 | dbg_printf("DO %s", option->name); 371 | else 372 | dbg_printf("DO #%d", buf[2]); 373 | 374 | if (option && option->sent_will) { 375 | /* 376 | * This is a confirmation of an WILL sent by us before. 377 | * There is nothing to do now. 378 | */ 379 | dbg_printf("\n"); 380 | } else { 381 | /* Oh, cannot handle that one, so send a WONT */ 382 | dbg_printf(" -> WONT\n"); 383 | telnet_printf(ios, "%c%c%c", IAC, WONT, buf[2]); 384 | } 385 | return 3; 386 | 387 | case DONT: 388 | option = get_telnet_option(buf[2]); 389 | if (option) 390 | dbg_printf("DONT %s\n", option->name); 391 | else 392 | dbg_printf("DONT #%d\n", buf[2]); 393 | return 3; 394 | 395 | default: 396 | dbg_printf("??? %d\n", buf[1]); 397 | return 1; 398 | } 399 | } 400 | 401 | static ssize_t telnet_write(struct ios_ops *ios, const void *buf, size_t count) 402 | { 403 | size_t handled = 0; 404 | ssize_t ret; 405 | void *iac; 406 | 407 | /* 408 | * To send an IAC character in the data stream, two IACs must be sent. 409 | * So find the first IAC in the data to be send (if any), send the data 410 | * before that IAC unquoted, then send the double IAC. Repeat until 411 | * all IACs are handled. 412 | */ 413 | while ((iac = memchr(buf + handled, IAC, count - handled)) != NULL) { 414 | if (iac - (buf + handled)) { 415 | ret = write(ios->fd, buf + handled, iac - (buf + handled)); 416 | if (ret < 0) 417 | return ret; 418 | handled += ret; 419 | } else { 420 | dprintf(ios->fd, "%c%c", IAC, IAC); 421 | handled += 1; 422 | } 423 | } 424 | 425 | /* Send the remaining data that needs no quoting. */ 426 | ret = write(ios->fd, buf + handled, count - handled); 427 | if (ret < 0) 428 | return ret; 429 | return ret + handled; 430 | } 431 | 432 | static ssize_t telnet_read(struct ios_ops *ios, void *buf, size_t count) 433 | { 434 | ssize_t ret = read(ios->fd, buf, count); 435 | void *iac; 436 | size_t handled = 0; 437 | 438 | if (ret <= 0) 439 | return ret; 440 | 441 | while ((iac = memchr(buf + handled, IAC, ret - handled)) != NULL) { 442 | handled = iac - buf; 443 | 444 | /* XXX: possible out-of-bounds access */ 445 | if (((unsigned char *)iac)[1] == IAC) { 446 | /* duplicated IAC = one payload IAC */ 447 | ret -= 1; 448 | memmove(iac, iac + 1, ret - (iac - buf)); 449 | handled += 1; 450 | } else { 451 | int iaclen = handle_command(ios, iac, ret - handled); 452 | 453 | if (iaclen < 0) 454 | return iaclen; 455 | 456 | memmove(iac, iac + iaclen, ret - (handled + iaclen)); 457 | ret -= iaclen; 458 | } 459 | } 460 | if (ret) { 461 | return ret; 462 | } else { 463 | errno = EAGAIN; 464 | return -1; 465 | } 466 | } 467 | 468 | static int telnet_set_speed(struct ios_ops *ios, unsigned long speed) 469 | { 470 | unsigned char buf2[14] = {IAC, SB, TELNET_OPTION_COM_PORT_CONTROL, SET_BAUDRATE_CS}; 471 | size_t offset = 4; 472 | int i; 473 | 474 | for (i = 0; i < 4; ++i) { 475 | buf2[offset] = (speed >> (24 - 8 * i)) & 0xff; 476 | if (buf2[offset++] == IAC) 477 | buf2[offset++] = IAC; 478 | } 479 | 480 | buf2[offset++] = IAC; 481 | buf2[offset++] = SE; 482 | 483 | dbg_printf("-> IAC SB COM_PORT_CONTROL SET_BAUDRATE_CS 0x%lx IAC SE\n", speed); 484 | write(ios->fd, buf2, offset); 485 | 486 | return 0; 487 | } 488 | 489 | static int telnet_set_flow(struct ios_ops *ios, int flow) 490 | { 491 | unsigned char buf2[] = {IAC, SB, TELNET_OPTION_COM_PORT_CONTROL, SET_CONTROL_CS, 0, IAC, SE}; 492 | 493 | switch (flow) { 494 | case FLOW_NONE: 495 | /* no flow control */ 496 | buf2[4] = 1; 497 | break; 498 | case FLOW_SOFT: 499 | /* software flow control */ 500 | buf2[4] = 2; 501 | break; 502 | case FLOW_HARD: 503 | /* hardware flow control */ 504 | buf2[4] = 3; 505 | break; 506 | } 507 | 508 | dbg_printf("-> IAC SB COM_PORT_CONTROL SET_CONTROL_CS %d IAC SE\n", buf2[4]); 509 | write(ios->fd, buf2, sizeof(buf2)); 510 | 511 | return 0; 512 | } 513 | 514 | static int telnet_send_break(struct ios_ops *ios) 515 | { 516 | unsigned char buf2[] = {IAC, BREAK}; 517 | 518 | write(ios->fd, buf2, sizeof(buf2)); 519 | 520 | return 0; 521 | } 522 | 523 | static void telnet_exit(struct ios_ops *ios) 524 | { 525 | close(ios->fd); 526 | free(ios); 527 | } 528 | 529 | struct ios_ops *telnet_init(char *hostport) 530 | { 531 | char *port; 532 | int ret; 533 | struct addrinfo *addrinfo, *ai; 534 | struct addrinfo hints; 535 | struct ios_ops *ios; 536 | char connected_host[256], connected_port[30]; 537 | 538 | ios = malloc(sizeof(*ios)); 539 | if (!ios) 540 | return NULL; 541 | 542 | ios->write = telnet_write; 543 | ios->read = telnet_read; 544 | ios->set_speed = telnet_set_speed; 545 | ios->set_flow = telnet_set_flow; 546 | ios->send_break = telnet_send_break; 547 | ios->exit = telnet_exit; 548 | 549 | memset(&hints, '\0', sizeof(hints)); 550 | hints.ai_flags = AI_ADDRCONFIG; 551 | hints.ai_socktype = SOCK_STREAM; 552 | 553 | if (hostport[0] == '[') { 554 | char *s = strchr(++hostport, ']'); 555 | 556 | if (s) 557 | /* terminate hostport after host portion */ 558 | *s = '\0'; 559 | 560 | if (s && s[1] == ':') 561 | port = s + 2; 562 | else if (s && s[1] == '\0') 563 | port = "23"; 564 | else { 565 | fprintf(stderr, "failed to parse host:port"); 566 | free(ios); 567 | return NULL; 568 | } 569 | } else { 570 | port = strchr(hostport, ':'); 571 | if (port) { 572 | /* terminate hostport after host portion */ 573 | *port = '\0'; 574 | 575 | port += 1; 576 | } else 577 | port = "23"; 578 | } 579 | 580 | ret = getaddrinfo(hostport, port, &hints, &addrinfo); 581 | if (ret) { 582 | fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); 583 | return NULL; 584 | } 585 | 586 | for (ai = addrinfo; ai != NULL; ai = ai->ai_next) { 587 | int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 588 | if (sock < 0) 589 | continue; 590 | 591 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 592 | close(sock); 593 | continue; 594 | } 595 | 596 | ios->fd = sock; 597 | 598 | ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, 599 | connected_host, sizeof(connected_host), 600 | connected_port, sizeof(connected_port), 601 | NI_NUMERICHOST | NI_NUMERICSERV); 602 | if (ret) { 603 | fprintf(stderr, "getnameinfo: %s\n", gai_strerror(ret)); 604 | goto out; 605 | } 606 | printf("connected to %s (port %s)\n", connected_host, connected_port); 607 | 608 | /* send intent we WILL do COM_PORT stuff */ 609 | dbg_printf("-> WILL COM_PORT_CONTROL\n"); 610 | dprintf(sock, "%c%c%c", IAC, WILL, TELNET_OPTION_COM_PORT_CONTROL); 611 | dbg_printf("-> DO BINARY_TRANSMISSION\n"); 612 | dprintf(sock, "%c%c%c", IAC, DO, TELNET_OPTION_BINARY_TRANSMISSION); 613 | dbg_printf("-> WILL BINARY_TRANSMISSION\n"); 614 | dprintf(sock, "%c%c%c", IAC, WILL, TELNET_OPTION_BINARY_TRANSMISSION); 615 | goto out; 616 | } 617 | 618 | perror("failed to connect"); 619 | free(ios); 620 | ios = NULL; 621 | out: 622 | freeaddrinfo(addrinfo); 623 | return ios; 624 | } 625 | 626 | --------------------------------------------------------------------------------